diff --git a/kernel/tools/perf/files/patches/aufs5/aufs5-base.patch b/kernel/tools/perf/files/patches/aufs5/aufs5-base.patch new file mode 100644 index 0000000000..42ebd27110 --- /dev/null +++ b/kernel/tools/perf/files/patches/aufs5/aufs5-base.patch @@ -0,0 +1,241 @@ +SPDX-License-Identifier: GPL-2.0 +aufs5.15.36 base patch + +diff --git a/MAINTAINERS b/MAINTAINERS +index c8103e57a70b..e1b9eaca78fd 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -3122,6 +3122,19 @@ F: include/uapi/linux/audit.h + F: kernel/audit* + F: lib/*audit.c + ++AUFS (advanced multi layered unification filesystem) FILESYSTEM ++M: "J. R. Okajima" ++L: aufs-users@lists.sourceforge.net (members only) ++L: linux-unionfs@vger.kernel.org ++S: Supported ++W: http://aufs.sourceforge.net ++T: git://github.com/sfjro/aufs4-linux.git ++F: Documentation/ABI/testing/debugfs-aufs ++F: Documentation/ABI/testing/sysfs-aufs ++F: Documentation/filesystems/aufs/ ++F: fs/aufs/ ++F: include/uapi/linux/aufs_type.h ++ + AUXILIARY DISPLAY DRIVERS + M: Miguel Ojeda + S: Maintained +diff --git a/drivers/block/loop.c b/drivers/block/loop.c +index 8cba10aafadb..7a9e40b97831 100644 +--- a/drivers/block/loop.c ++++ b/drivers/block/loop.c +@@ -799,6 +799,24 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, + return error; + } + ++/* ++ * for AUFS ++ * no get/put for file. ++ */ ++struct file *loop_backing_file(struct super_block *sb) ++{ ++ struct file *ret; ++ struct loop_device *l; ++ ++ ret = NULL; ++ if (MAJOR(sb->s_dev) == LOOP_MAJOR) { ++ l = sb->s_bdev->bd_disk->private_data; ++ ret = l->lo_backing_file; ++ } ++ return ret; ++} ++EXPORT_SYMBOL_GPL(loop_backing_file); ++ + /* loop sysfs attributes */ + + static ssize_t loop_attr_show(struct device *dev, char *page, +diff --git a/fs/dcache.c b/fs/dcache.c +index cf871a81f4fd..bc5095b734f5 100644 +--- a/fs/dcache.c ++++ b/fs/dcache.c +@@ -1320,7 +1320,7 @@ enum d_walk_ret { + * + * The @enter() callbacks are called with d_lock held. + */ +-static void d_walk(struct dentry *parent, void *data, ++void d_walk(struct dentry *parent, void *data, + enum d_walk_ret (*enter)(void *, struct dentry *)) + { + struct dentry *this_parent; +diff --git a/fs/fcntl.c b/fs/fcntl.c +index 9c6c6a3e2de5..02382fa9bd34 100644 +--- a/fs/fcntl.c ++++ b/fs/fcntl.c +@@ -33,7 +33,7 @@ + + #define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT | O_NOATIME) + +-static int setfl(int fd, struct file * filp, unsigned long arg) ++int setfl(int fd, struct file *filp, unsigned long arg) + { + struct inode * inode = file_inode(filp); + int error = 0; +@@ -64,6 +64,8 @@ static int setfl(int fd, struct file * filp, unsigned long arg) + + if (filp->f_op->check_flags) + error = filp->f_op->check_flags(arg); ++ if (!error && filp->f_op->setfl) ++ error = filp->f_op->setfl(filp, arg); + if (error) + return error; + +diff --git a/fs/namespace.c b/fs/namespace.c +index b696543adab8..c45740054bc7 100644 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -808,6 +808,12 @@ static inline int check_mnt(struct mount *mnt) + return mnt->mnt_ns == current->nsproxy->mnt_ns; + } + ++/* for aufs, CONFIG_AUFS_BR_FUSE */ ++int is_current_mnt_ns(struct vfsmount *mnt) ++{ ++ return check_mnt(real_mount(mnt)); ++} ++ + /* + * vfsmount lock must be held for write + */ +diff --git a/fs/splice.c b/fs/splice.c +index 5dbce4dcc1a7..3e6ba363b777 100644 +--- a/fs/splice.c ++++ b/fs/splice.c +@@ -759,8 +759,8 @@ static int warn_unsupported(struct file *file, const char *op) + /* + * Attempt to initiate a splice from pipe to file. + */ +-static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, +- loff_t *ppos, size_t len, unsigned int flags) ++long do_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags) + { + if (unlikely(!out->f_op->splice_write)) + return warn_unsupported(out, "write"); +@@ -770,9 +770,9 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, + /* + * Attempt to initiate a splice from a file to a pipe. + */ +-static long do_splice_to(struct file *in, loff_t *ppos, +- struct pipe_inode_info *pipe, size_t len, +- unsigned int flags) ++long do_splice_to(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags) + { + unsigned int p_space; + int ret; +diff --git a/include/linux/fs.h b/include/linux/fs.h +index 56eba723477e..e60d8ad85400 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -1381,6 +1381,7 @@ extern void fasync_free(struct fasync_struct *); + /* can be called from interrupts */ + extern void kill_fasync(struct fasync_struct **, int, int); + ++extern int setfl(int fd, struct file *filp, unsigned long arg); + extern void __f_setown(struct file *filp, struct pid *, enum pid_type, int force); + extern int f_setown(struct file *filp, unsigned long arg, int force); + extern void f_delown(struct file *filp); +@@ -2092,6 +2093,7 @@ struct file_operations { + ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); + unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); + int (*check_flags)(int); ++ int (*setfl)(struct file *, unsigned long); + int (*flock) (struct file *, int, struct file_lock *); + ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); + ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); +@@ -2615,6 +2617,7 @@ extern int current_umask(void); + extern void ihold(struct inode * inode); + extern void iput(struct inode *); + extern int generic_update_time(struct inode *, struct timespec64 *, int); ++extern int update_time(struct inode *, struct timespec64 *, int); + + /* /sys/fs */ + extern struct kobject *fs_kobj; +@@ -2778,6 +2781,7 @@ static inline bool sb_is_blkdev_sb(struct super_block *sb) + } + + void emergency_thaw_all(void); ++extern int __sync_filesystem(struct super_block *, int); + extern int sync_filesystem(struct super_block *); + extern const struct file_operations def_blk_fops; + extern const struct file_operations def_chr_fops; +diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h +index 9fe165beb0f9..e47f7e15eeaf 100644 +--- a/include/linux/lockdep.h ++++ b/include/linux/lockdep.h +@@ -248,6 +248,8 @@ static inline int lockdep_match_key(struct lockdep_map *lock, + return lock->key == key; + } + ++struct lock_class *lockdep_hlock_class(struct held_lock *hlock); ++ + /* + * Acquire a lock. + * +diff --git a/include/linux/mnt_namespace.h b/include/linux/mnt_namespace.h +index 8f882f5881e8..6b9808f09843 100644 +--- a/include/linux/mnt_namespace.h ++++ b/include/linux/mnt_namespace.h +@@ -7,12 +7,15 @@ struct mnt_namespace; + struct fs_struct; + struct user_namespace; + struct ns_common; ++struct vfsmount; + + extern struct mnt_namespace *copy_mnt_ns(unsigned long, struct mnt_namespace *, + struct user_namespace *, struct fs_struct *); + extern void put_mnt_ns(struct mnt_namespace *ns); + extern struct ns_common *from_mnt_ns(struct mnt_namespace *); + ++extern int is_current_mnt_ns(struct vfsmount *mnt); ++ + extern const struct file_operations proc_mounts_operations; + extern const struct file_operations proc_mountinfo_operations; + extern const struct file_operations proc_mountstats_operations; +diff --git a/include/linux/splice.h b/include/linux/splice.h +index a55179fd60fc..8e21c53cf883 100644 +--- a/include/linux/splice.h ++++ b/include/linux/splice.h +@@ -93,4 +93,10 @@ extern void splice_shrink_spd(struct splice_pipe_desc *); + + extern const struct pipe_buf_operations page_cache_pipe_buf_ops; + extern const struct pipe_buf_operations default_pipe_buf_ops; ++ ++extern long do_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags); ++extern long do_splice_to(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags); + #endif +diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c +index a30702b847ba..ce380d0abdf0 100644 +--- a/kernel/locking/lockdep.c ++++ b/kernel/locking/lockdep.c +@@ -187,7 +187,7 @@ unsigned long max_lock_class_idx; + struct lock_class lock_classes[MAX_LOCKDEP_KEYS]; + DECLARE_BITMAP(lock_classes_in_use, MAX_LOCKDEP_KEYS); + +-static inline struct lock_class *hlock_class(struct held_lock *hlock) ++inline struct lock_class *lockdep_hlock_class(struct held_lock *hlock) + { + unsigned int class_idx = hlock->class_idx; + +@@ -208,6 +208,7 @@ static inline struct lock_class *hlock_class(struct held_lock *hlock) + */ + return lock_classes + class_idx; + } ++#define hlock_class(hlock) lockdep_hlock_class(hlock) + + #ifdef CONFIG_LOCK_STAT + static DEFINE_PER_CPU(struct lock_class_stats[MAX_LOCKDEP_KEYS], cpu_lock_stats); diff --git a/kernel/tools/perf/files/patches/aufs5/aufs5-kbuild.patch b/kernel/tools/perf/files/patches/aufs5/aufs5-kbuild.patch new file mode 100644 index 0000000000..79c3f92c55 --- /dev/null +++ b/kernel/tools/perf/files/patches/aufs5/aufs5-kbuild.patch @@ -0,0 +1,24 @@ +SPDX-License-Identifier: GPL-2.0 +aufs5.15.36 kbuild patch + +diff --git a/fs/Kconfig b/fs/Kconfig +index a6313a969bc5..aca4b89d41a1 100644 +--- a/fs/Kconfig ++++ b/fs/Kconfig +@@ -312,6 +312,7 @@ source "fs/sysv/Kconfig" + source "fs/ufs/Kconfig" + source "fs/erofs/Kconfig" + source "fs/vboxsf/Kconfig" ++source "fs/aufs/Kconfig" + + endif # MISC_FILESYSTEMS + +diff --git a/fs/Makefile b/fs/Makefile +index 84c5e4cdfee5..b4fcdad8412e 100644 +--- a/fs/Makefile ++++ b/fs/Makefile +@@ -138,3 +138,4 @@ obj-$(CONFIG_EFIVAR_FS) += efivarfs/ + obj-$(CONFIG_EROFS_FS) += erofs/ + obj-$(CONFIG_VBOXSF_FS) += vboxsf/ + obj-$(CONFIG_ZONEFS_FS) += zonefs/ ++obj-$(CONFIG_AUFS_FS) += aufs/ diff --git a/kernel/tools/perf/files/patches/aufs5/aufs5-loopback.patch b/kernel/tools/perf/files/patches/aufs5/aufs5-loopback.patch new file mode 100644 index 0000000000..1011fb54a4 --- /dev/null +++ b/kernel/tools/perf/files/patches/aufs5/aufs5-loopback.patch @@ -0,0 +1,244 @@ +SPDX-License-Identifier: GPL-2.0 +aufs5.15.36 loopback patch + +diff --git a/drivers/block/loop.c b/drivers/block/loop.c +index 7a9e40b97831..5ed06240cc9c 100644 +--- a/drivers/block/loop.c ++++ b/drivers/block/loop.c +@@ -673,6 +673,15 @@ static inline void loop_update_dio(struct loop_device *lo) + lo->use_dio); + } + ++static struct file *loop_real_file(struct file *file) ++{ ++ struct file *f = NULL; ++ ++ if (file->f_path.dentry->d_sb->s_op->real_loop) ++ f = file->f_path.dentry->d_sb->s_op->real_loop(file); ++ return f; ++} ++ + static void loop_reread_partitions(struct loop_device *lo) + { + int rc; +@@ -730,6 +739,7 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, + { + struct file *file = fget(arg); + struct file *old_file; ++ struct file *f, *virt_file = NULL, *old_virt_file; + int error; + bool partscan; + bool is_loop; +@@ -749,11 +759,19 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, + if (!(lo->lo_flags & LO_FLAGS_READ_ONLY)) + goto out_err; + ++ f = loop_real_file(file); ++ if (f) { ++ virt_file = file; ++ file = f; ++ get_file(file); ++ } ++ + error = loop_validate_file(file, bdev); + if (error) + goto out_err; + + old_file = lo->lo_backing_file; ++ old_virt_file = lo->lo_backing_virt_file; + + error = -EINVAL; + +@@ -766,6 +784,7 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, + blk_mq_freeze_queue(lo->lo_queue); + mapping_set_gfp_mask(old_file->f_mapping, lo->old_gfp_mask); + lo->lo_backing_file = file; ++ lo->lo_backing_virt_file = virt_file; + lo->old_gfp_mask = mapping_gfp_mask(file->f_mapping); + mapping_set_gfp_mask(file->f_mapping, + lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS)); +@@ -788,6 +807,8 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, + * dependency. + */ + fput(old_file); ++ if (old_virt_file) ++ fput(old_virt_file); + if (partscan) + loop_reread_partitions(lo); + return 0; +@@ -796,6 +817,8 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, + loop_global_unlock(lo, is_loop); + out_putf: + fput(file); ++ if (virt_file) ++ fput(virt_file); + return error; + } + +@@ -1201,6 +1224,7 @@ static int loop_configure(struct loop_device *lo, fmode_t mode, + const struct loop_config *config) + { + struct file *file = fget(config->fd); ++ struct file *f, *virt_file = NULL; + struct inode *inode; + struct address_space *mapping; + int error; +@@ -1216,6 +1240,13 @@ static int loop_configure(struct loop_device *lo, fmode_t mode, + /* This is safe, since we have a reference from open(). */ + __module_get(THIS_MODULE); + ++ f = loop_real_file(file); ++ if (f) { ++ virt_file = file; ++ file = f; ++ get_file(file); ++ } ++ + /* + * If we don't hold exclusive handle for the device, upgrade to it + * here to avoid changing device under exclusive owner. +@@ -1281,6 +1312,7 @@ static int loop_configure(struct loop_device *lo, fmode_t mode, + lo->use_dio = lo->lo_flags & LO_FLAGS_DIRECT_IO; + lo->lo_device = bdev; + lo->lo_backing_file = file; ++ lo->lo_backing_virt_file = virt_file; + lo->old_gfp_mask = mapping_gfp_mask(mapping); + mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS)); + +@@ -1331,6 +1363,8 @@ static int loop_configure(struct loop_device *lo, fmode_t mode, + bd_abort_claiming(bdev, loop_configure); + out_putf: + fput(file); ++ if (virt_file) ++ fput(virt_file); + /* This is safe: open() is still holding a reference. */ + module_put(THIS_MODULE); + return error; +@@ -1339,6 +1373,7 @@ static int loop_configure(struct loop_device *lo, fmode_t mode, + static int __loop_clr_fd(struct loop_device *lo, bool release) + { + struct file *filp = NULL; ++ struct file *virt_filp = lo->lo_backing_virt_file; + gfp_t gfp = lo->old_gfp_mask; + struct block_device *bdev = lo->lo_device; + int err = 0; +@@ -1390,6 +1425,7 @@ static int __loop_clr_fd(struct loop_device *lo, bool release) + + spin_lock_irq(&lo->lo_lock); + lo->lo_backing_file = NULL; ++ lo->lo_backing_virt_file = NULL; + spin_unlock_irq(&lo->lo_lock); + + loop_release_xfer(lo); +@@ -1470,6 +1506,8 @@ static int __loop_clr_fd(struct loop_device *lo, bool release) + */ + if (filp) + fput(filp); ++ if (virt_filp) ++ fput(virt_filp); + return err; + } + +diff --git a/drivers/block/loop.h b/drivers/block/loop.h +index 04c88dd6eabd..0ff3ba22ee17 100644 +--- a/drivers/block/loop.h ++++ b/drivers/block/loop.h +@@ -46,7 +46,7 @@ struct loop_device { + int (*ioctl)(struct loop_device *, int cmd, + unsigned long arg); + +- struct file * lo_backing_file; ++ struct file *lo_backing_file, *lo_backing_virt_file; + struct block_device *lo_device; + void *key_data; + +diff --git a/fs/aufs/f_op.c b/fs/aufs/f_op.c +index 99ceca144044..e49dfe855032 100644 +--- a/fs/aufs/f_op.c ++++ b/fs/aufs/f_op.c +@@ -304,7 +304,7 @@ static ssize_t aufs_read_iter(struct kiocb *kio, struct iov_iter *iov_iter) + if (IS_ERR(h_file)) + goto out; + +- if (au_test_loopback_kthread()) { ++ if (0 && au_test_loopback_kthread()) { + au_warn_loopback(h_file->f_path.dentry->d_sb); + if (file->f_mapping != h_file->f_mapping) { + file->f_mapping = h_file->f_mapping; +diff --git a/fs/aufs/loop.c b/fs/aufs/loop.c +index 74347bd75b38..5ef888a1d53f 100644 +--- a/fs/aufs/loop.c ++++ b/fs/aufs/loop.c +@@ -133,3 +133,19 @@ void au_loopback_fin(void) + symbol_put(loop_backing_file); + au_kfree_try_rcu(au_warn_loopback_array); + } ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* support the loopback block device insude aufs */ ++ ++struct file *aufs_real_loop(struct file *file) ++{ ++ struct file *f; ++ ++ BUG_ON(!au_test_aufs(file->f_path.dentry->d_sb)); ++ fi_read_lock(file); ++ f = au_hf_top(file); ++ fi_read_unlock(file); ++ AuDebugOn(!f); ++ return f; ++} +diff --git a/fs/aufs/loop.h b/fs/aufs/loop.h +index 7293bee427f9..3345c098d0d4 100644 +--- a/fs/aufs/loop.h ++++ b/fs/aufs/loop.h +@@ -26,6 +26,8 @@ void au_warn_loopback(struct super_block *h_sb); + + int au_loopback_init(void); + void au_loopback_fin(void); ++ ++struct file *aufs_real_loop(struct file *file); + #else + AuStub(struct file *, loop_backing_file, return NULL, struct super_block *sb) + +@@ -36,6 +38,8 @@ AuStubVoid(au_warn_loopback, struct super_block *h_sb) + + AuStubInt0(au_loopback_init, void) + AuStubVoid(au_loopback_fin, void) ++ ++AuStub(struct file *, aufs_real_loop, return NULL, struct file *file) + #endif /* BLK_DEV_LOOP */ + + #endif /* __KERNEL__ */ +diff --git a/fs/aufs/super.c b/fs/aufs/super.c +index 90043afec51c..0835f6da42d9 100644 +--- a/fs/aufs/super.c ++++ b/fs/aufs/super.c +@@ -758,7 +758,10 @@ const struct super_operations aufs_sop = { + .show_options = aufs_show_options, + .statfs = aufs_statfs, + .put_super = aufs_put_super, +- .sync_fs = aufs_sync_fs ++ .sync_fs = aufs_sync_fs, ++#ifdef CONFIG_AUFS_BDEV_LOOP ++ .real_loop = aufs_real_loop ++#endif + }; + + /* ---------------------------------------------------------------------- */ +diff --git a/include/linux/fs.h b/include/linux/fs.h +index e60d8ad85400..2ac5317f9b79 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -2226,6 +2226,10 @@ struct super_operations { + struct shrink_control *); + long (*free_cached_objects)(struct super_block *, + struct shrink_control *); ++#if IS_ENABLED(CONFIG_BLK_DEV_LOOP) || IS_ENABLED(CONFIG_BLK_DEV_LOOP_MODULE) ++ /* and aufs */ ++ struct file *(*real_loop)(struct file *); ++#endif + }; + + /* diff --git a/kernel/tools/perf/files/patches/aufs5/aufs5-mmap.patch b/kernel/tools/perf/files/patches/aufs5/aufs5-mmap.patch new file mode 100644 index 0000000000..a8b2040c77 --- /dev/null +++ b/kernel/tools/perf/files/patches/aufs5/aufs5-mmap.patch @@ -0,0 +1,419 @@ +SPDX-License-Identifier: GPL-2.0 +aufs5.15.36 mmap patch + +diff --git a/fs/proc/base.c b/fs/proc/base.c +index 1f394095eb88..93f2479ef319 100644 +--- a/fs/proc/base.c ++++ b/fs/proc/base.c +@@ -2189,7 +2189,7 @@ static int map_files_get_link(struct dentry *dentry, struct path *path) + rc = -ENOENT; + vma = find_exact_vma(mm, vm_start, vm_end); + if (vma && vma->vm_file) { +- *path = vma->vm_file->f_path; ++ *path = vma_pr_or_file(vma)->f_path; + path_get(path); + rc = 0; + } +diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c +index 13452b32e2bd..38acccfef9d4 100644 +--- a/fs/proc/nommu.c ++++ b/fs/proc/nommu.c +@@ -40,7 +40,10 @@ static int nommu_region_show(struct seq_file *m, struct vm_region *region) + file = region->vm_file; + + if (file) { +- struct inode *inode = file_inode(region->vm_file); ++ struct inode *inode; ++ ++ file = vmr_pr_or_file(region); ++ inode = file_inode(file); + dev = inode->i_sb->s_dev; + ino = inode->i_ino; + } +diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c +index 79ca4d69dfd6..3d3067c8d868 100644 +--- a/fs/proc/task_mmu.c ++++ b/fs/proc/task_mmu.c +@@ -280,7 +280,10 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma) + const char *name = NULL; + + if (file) { +- struct inode *inode = file_inode(vma->vm_file); ++ struct inode *inode; ++ ++ file = vma_pr_or_file(vma); ++ inode = file_inode(file); + dev = inode->i_sb->s_dev; + ino = inode->i_ino; + pgoff = ((loff_t)vma->vm_pgoff) << PAGE_SHIFT; +@@ -1888,7 +1891,7 @@ static int show_numa_map(struct seq_file *m, void *v) + struct proc_maps_private *proc_priv = &numa_priv->proc_maps; + struct vm_area_struct *vma = v; + struct numa_maps *md = &numa_priv->md; +- struct file *file = vma->vm_file; ++ struct file *file = vma_pr_or_file(vma); + struct mm_struct *mm = vma->vm_mm; + struct mempolicy *pol; + char buffer[64]; +diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c +index a6d21fc0033c..02c2de31196e 100644 +--- a/fs/proc/task_nommu.c ++++ b/fs/proc/task_nommu.c +@@ -155,7 +155,10 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma) + file = vma->vm_file; + + if (file) { +- struct inode *inode = file_inode(vma->vm_file); ++ struct inode *inode; ++ ++ file = vma_pr_or_file(vma); ++ inode = file_inode(file); + dev = inode->i_sb->s_dev; + ino = inode->i_ino; + pgoff = (loff_t)vma->vm_pgoff << PAGE_SHIFT; +diff --git a/include/linux/mm.h b/include/linux/mm.h +index 90c2d7f3c7a8..ab1b20fa5837 100644 +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -1813,6 +1813,43 @@ static inline void unmap_shared_mapping_range(struct address_space *mapping, + unmap_mapping_range(mapping, holebegin, holelen, 0); + } + ++#if IS_ENABLED(CONFIG_AUFS_FS) ++extern void vma_do_file_update_time(struct vm_area_struct *, const char[], int); ++extern struct file *vma_do_pr_or_file(struct vm_area_struct *, const char[], ++ int); ++extern void vma_do_get_file(struct vm_area_struct *, const char[], int); ++extern void vma_do_fput(struct vm_area_struct *, const char[], int); ++ ++#define vma_file_update_time(vma) vma_do_file_update_time(vma, __func__, \ ++ __LINE__) ++#define vma_pr_or_file(vma) vma_do_pr_or_file(vma, __func__, \ ++ __LINE__) ++#define vma_get_file(vma) vma_do_get_file(vma, __func__, __LINE__) ++#define vma_fput(vma) vma_do_fput(vma, __func__, __LINE__) ++ ++#ifndef CONFIG_MMU ++extern struct file *vmr_do_pr_or_file(struct vm_region *, const char[], int); ++extern void vmr_do_fput(struct vm_region *, const char[], int); ++ ++#define vmr_pr_or_file(region) vmr_do_pr_or_file(region, __func__, \ ++ __LINE__) ++#define vmr_fput(region) vmr_do_fput(region, __func__, __LINE__) ++#endif /* !CONFIG_MMU */ ++ ++#else ++ ++#define vma_file_update_time(vma) file_update_time((vma)->vm_file) ++#define vma_pr_or_file(vma) (vma)->vm_file ++#define vma_get_file(vma) get_file((vma)->vm_file) ++#define vma_fput(vma) fput((vma)->vm_file) ++ ++#ifndef CONFIG_MMU ++#define vmr_pr_or_file(region) (region)->vm_file ++#define vmr_fput(region) fput((region)->vm_file) ++#endif /* !CONFIG_MMU */ ++ ++#endif /* CONFIG_AUFS_FS */ ++ + extern int access_process_vm(struct task_struct *tsk, unsigned long addr, + void *buf, int len, unsigned int gup_flags); + extern int access_remote_vm(struct mm_struct *mm, unsigned long addr, +diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h +index 7f8ee09c711f..8fea872e08f7 100644 +--- a/include/linux/mm_types.h ++++ b/include/linux/mm_types.h +@@ -294,6 +294,9 @@ struct vm_region { + unsigned long vm_top; /* region allocated to here */ + unsigned long vm_pgoff; /* the offset in vm_file corresponding to vm_start */ + struct file *vm_file; /* the backing file or NULL */ ++#if IS_ENABLED(CONFIG_AUFS_FS) ++ struct file *vm_prfile; /* the virtual backing file or NULL */ ++#endif + + int vm_usage; /* region usage count (access under nommu_region_sem) */ + bool vm_icache_flushed : 1; /* true if the icache has been flushed for +@@ -373,6 +376,9 @@ struct vm_area_struct { + unsigned long vm_pgoff; /* Offset (within vm_file) in PAGE_SIZE + units */ + struct file * vm_file; /* File we map to (can be NULL). */ ++#if IS_ENABLED(CONFIG_AUFS_FS) ++ struct file *vm_prfile; /* shadow of vm_file */ ++#endif + void * vm_private_data; /* was vm_pte (shared mem) */ + + #ifdef CONFIG_SWAP +diff --git a/kernel/fork.c b/kernel/fork.c +index 89475c994ca9..82f46f8f4090 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -573,7 +573,7 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm, + if (file) { + struct address_space *mapping = file->f_mapping; + +- get_file(file); ++ vma_get_file(tmp); + i_mmap_lock_write(mapping); + if (tmp->vm_flags & VM_SHARED) + mapping_allow_writable(mapping); +diff --git a/mm/Makefile b/mm/Makefile +index fc60a40ce954..d45773672730 100644 +--- a/mm/Makefile ++++ b/mm/Makefile +@@ -130,3 +130,4 @@ obj-$(CONFIG_PAGE_REPORTING) += page_reporting.o + obj-$(CONFIG_IO_MAPPING) += io-mapping.o + obj-$(CONFIG_HAVE_BOOTMEM_INFO_NODE) += bootmem_info.o + obj-$(CONFIG_GENERIC_IOREMAP) += ioremap.o ++obj-$(CONFIG_AUFS_FS:m=y) += prfile.o +diff --git a/mm/filemap.c b/mm/filemap.c +index 1293c3409e42..42b012b99f4e 100644 +--- a/mm/filemap.c ++++ b/mm/filemap.c +@@ -3353,7 +3353,7 @@ vm_fault_t filemap_page_mkwrite(struct vm_fault *vmf) + vm_fault_t ret = VM_FAULT_LOCKED; + + sb_start_pagefault(mapping->host->i_sb); +- file_update_time(vmf->vma->vm_file); ++ vma_file_update_time(vmf->vma); + lock_page(page); + if (page->mapping != mapping) { + unlock_page(page); +diff --git a/mm/mmap.c b/mm/mmap.c +index 6bb553ed5c55..3f9d6d155171 100644 +--- a/mm/mmap.c ++++ b/mm/mmap.c +@@ -183,7 +183,7 @@ static struct vm_area_struct *remove_vma(struct vm_area_struct *vma) + if (vma->vm_ops && vma->vm_ops->close) + vma->vm_ops->close(vma); + if (vma->vm_file) +- fput(vma->vm_file); ++ vma_fput(vma); + mpol_put(vma_policy(vma)); + vm_area_free(vma); + return next; +@@ -952,7 +952,7 @@ int __vma_adjust(struct vm_area_struct *vma, unsigned long start, + if (remove_next) { + if (file) { + uprobe_munmap(next, next->vm_start, next->vm_end); +- fput(file); ++ vma_fput(vma); + } + if (next->anon_vma) + anon_vma_merge(vma, next); +@@ -1873,7 +1873,7 @@ unsigned long mmap_region(struct file *file, unsigned long addr, + return addr; + + unmap_and_free_vma: +- fput(vma->vm_file); ++ vma_fput(vma); + vma->vm_file = NULL; + + /* Undo any partial mapping done by a device driver. */ +@@ -2723,7 +2723,7 @@ int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma, + goto out_free_mpol; + + if (new->vm_file) +- get_file(new->vm_file); ++ vma_get_file(new); + + if (new->vm_ops && new->vm_ops->open) + new->vm_ops->open(new); +@@ -2742,7 +2742,7 @@ int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma, + if (new->vm_ops && new->vm_ops->close) + new->vm_ops->close(new); + if (new->vm_file) +- fput(new->vm_file); ++ vma_fput(new); + unlink_anon_vmas(new); + out_free_mpol: + mpol_put(vma_policy(new)); +@@ -2938,6 +2938,9 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size, + unsigned long populate = 0; + unsigned long ret = -EINVAL; + struct file *file; ++#if IS_ENABLED(CONFIG_AUFS_FS) ++ struct file *prfile; ++#endif + + pr_warn_once("%s (%d) uses deprecated remap_file_pages() syscall. See Documentation/vm/remap_file_pages.rst.\n", + current->comm, current->pid); +@@ -2993,10 +2996,34 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size, + if (vma->vm_flags & VM_LOCKED) + flags |= MAP_LOCKED; + ++#if IS_ENABLED(CONFIG_AUFS_FS) ++ vma_get_file(vma); ++ file = vma->vm_file; ++ prfile = vma->vm_prfile; ++ ret = do_mmap(vma->vm_file, start, size, ++ prot, flags, pgoff, &populate, NULL); ++ if (!IS_ERR_VALUE(ret) && file && prfile) { ++ struct vm_area_struct *new_vma; ++ ++ new_vma = find_vma(mm, ret); ++ if (!new_vma->vm_prfile) ++ new_vma->vm_prfile = prfile; ++ if (new_vma != vma) ++ get_file(prfile); ++ } ++ /* ++ * two fput()s instead of vma_fput(vma), ++ * coz vma may not be available anymore. ++ */ ++ fput(file); ++ if (prfile) ++ fput(prfile); ++#else + file = get_file(vma->vm_file); + ret = do_mmap(vma->vm_file, start, size, + prot, flags, pgoff, &populate, NULL); + fput(file); ++#endif /* CONFIG_AUFS_FS */ + out: + mmap_write_unlock(mm); + if (populate) +@@ -3277,7 +3304,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, + if (anon_vma_clone(new_vma, vma)) + goto out_free_mempol; + if (new_vma->vm_file) +- get_file(new_vma->vm_file); ++ vma_get_file(new_vma); + if (new_vma->vm_ops && new_vma->vm_ops->open) + new_vma->vm_ops->open(new_vma); + vma_link(mm, new_vma, prev, rb_link, rb_parent); +diff --git a/mm/nommu.c b/mm/nommu.c +index 02d2427b8f9e..a7419302ab4e 100644 +--- a/mm/nommu.c ++++ b/mm/nommu.c +@@ -523,7 +523,7 @@ static void __put_nommu_region(struct vm_region *region) + up_write(&nommu_region_sem); + + if (region->vm_file) +- fput(region->vm_file); ++ vmr_fput(region); + + /* IO memory and memory shared directly out of the pagecache + * from ramfs/tmpfs mustn't be released here */ +@@ -655,7 +655,7 @@ static void delete_vma(struct mm_struct *mm, struct vm_area_struct *vma) + if (vma->vm_ops && vma->vm_ops->close) + vma->vm_ops->close(vma); + if (vma->vm_file) +- fput(vma->vm_file); ++ vma_fput(vma); + put_nommu_region(vma->vm_region); + vm_area_free(vma); + } +@@ -1175,7 +1175,7 @@ unsigned long do_mmap(struct file *file, + goto error_just_free; + } + } +- fput(region->vm_file); ++ vmr_fput(region); + kmem_cache_free(vm_region_jar, region); + region = pregion; + result = start; +@@ -1252,10 +1252,10 @@ unsigned long do_mmap(struct file *file, + up_write(&nommu_region_sem); + error: + if (region->vm_file) +- fput(region->vm_file); ++ vmr_fput(region); + kmem_cache_free(vm_region_jar, region); + if (vma->vm_file) +- fput(vma->vm_file); ++ vma_fput(vma); + vm_area_free(vma); + return ret; + +diff --git a/mm/prfile.c b/mm/prfile.c +new file mode 100644 +index 000000000000..511543ab1b41 +--- /dev/null ++++ b/mm/prfile.c +@@ -0,0 +1,86 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Mainly for aufs which mmap(2) different file and wants to print different ++ * path in /proc/PID/maps. ++ * Call these functions via macros defined in linux/mm.h. ++ * ++ * See Documentation/filesystems/aufs/design/06mmap.txt ++ * ++ * Copyright (c) 2014-2021 Junjro R. Okajima ++ * Copyright (c) 2014 Ian Campbell ++ */ ++ ++#include ++#include ++#include ++ ++/* #define PRFILE_TRACE */ ++static inline void prfile_trace(struct file *f, struct file *pr, ++ const char func[], int line, const char func2[]) ++{ ++#ifdef PRFILE_TRACE ++ if (pr) ++ pr_info("%s:%d: %s, %pD2\n", func, line, func2, f); ++#endif ++} ++ ++void vma_do_file_update_time(struct vm_area_struct *vma, const char func[], ++ int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ file_update_time(f); ++ if (f && pr) ++ file_update_time(pr); ++} ++ ++struct file *vma_do_pr_or_file(struct vm_area_struct *vma, const char func[], ++ int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ return (f && pr) ? pr : f; ++} ++ ++void vma_do_get_file(struct vm_area_struct *vma, const char func[], int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ get_file(f); ++ if (f && pr) ++ get_file(pr); ++} ++ ++void vma_do_fput(struct vm_area_struct *vma, const char func[], int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ fput(f); ++ if (f && pr) ++ fput(pr); ++} ++ ++#ifndef CONFIG_MMU ++struct file *vmr_do_pr_or_file(struct vm_region *region, const char func[], ++ int line) ++{ ++ struct file *f = region->vm_file, *pr = region->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ return (f && pr) ? pr : f; ++} ++ ++void vmr_do_fput(struct vm_region *region, const char func[], int line) ++{ ++ struct file *f = region->vm_file, *pr = region->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ fput(f); ++ if (f && pr) ++ fput(pr); ++} ++#endif /* !CONFIG_MMU */ diff --git a/kernel/tools/perf/files/patches/aufs5/aufs5-standalone.patch b/kernel/tools/perf/files/patches/aufs5/aufs5-standalone.patch new file mode 100644 index 0000000000..63d24760ff --- /dev/null +++ b/kernel/tools/perf/files/patches/aufs5/aufs5-standalone.patch @@ -0,0 +1,251 @@ +SPDX-License-Identifier: GPL-2.0 +aufs5.15.36 standalone patch + +diff --git a/fs/dcache.c b/fs/dcache.c +index bc5095b734f5..9508bd57a3bc 100644 +--- a/fs/dcache.c ++++ b/fs/dcache.c +@@ -1425,6 +1425,7 @@ void d_walk(struct dentry *parent, void *data, + seq = 1; + goto again; + } ++EXPORT_SYMBOL_GPL(d_walk); + + struct check_mount { + struct vfsmount *mnt; +@@ -2970,6 +2971,7 @@ void d_exchange(struct dentry *dentry1, struct dentry *dentry2) + + write_sequnlock(&rename_lock); + } ++EXPORT_SYMBOL_GPL(d_exchange); + + /** + * d_ancestor - search for an ancestor +diff --git a/fs/exec.c b/fs/exec.c +index 29e865c59854..3ea36fa14622 100644 +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -111,6 +111,7 @@ bool path_noexec(const struct path *path) + return (path->mnt->mnt_flags & MNT_NOEXEC) || + (path->mnt->mnt_sb->s_iflags & SB_I_NOEXEC); + } ++EXPORT_SYMBOL_GPL(path_noexec); + + #ifdef CONFIG_USELIB + /* +diff --git a/fs/fcntl.c b/fs/fcntl.c +index 02382fa9bd34..3418c60b9014 100644 +--- a/fs/fcntl.c ++++ b/fs/fcntl.c +@@ -86,6 +86,7 @@ int setfl(int fd, struct file *filp, unsigned long arg) + out: + return error; + } ++EXPORT_SYMBOL_GPL(setfl); + + static void f_modown(struct file *filp, struct pid *pid, enum pid_type type, + int force) +diff -Nurp a/fs/file_table.c b/fs/file_table.c +--- a/fs/file_table.c 2022-03-20 22:14:17.000000000 +0200 ++++ b/fs/file_table.c 2022-04-08 20:24:23.624148779 +0300 +@@ -198,6 +198,7 @@ over: + } + return ERR_PTR(-ENFILE); + } ++EXPORT_SYMBOL_GPL(alloc_empty_file); + + /* + * Variant of alloc_empty_file() that doesn't check and modify nr_files. +diff --git a/fs/namespace.c b/fs/namespace.c +index c45740054bc7..d3d750635610 100644 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -439,6 +439,7 @@ void __mnt_drop_write(struct vfsmount *mnt) + mnt_dec_writers(real_mount(mnt)); + preempt_enable(); + } ++EXPORT_SYMBOL_GPL(__mnt_drop_write); + + /** + * mnt_drop_write - give up write access to a mount +@@ -813,6 +814,7 @@ int is_current_mnt_ns(struct vfsmount *mnt) + { + return check_mnt(real_mount(mnt)); + } ++EXPORT_SYMBOL_GPL(is_current_mnt_ns); + + /* + * vfsmount lock must be held for write +@@ -2011,6 +2013,7 @@ int iterate_mounts(int (*f)(struct vfsmount *, void *), void *arg, + } + return 0; + } ++EXPORT_SYMBOL_GPL(iterate_mounts); + + static void lock_mnt_tree(struct mount *mnt) + { +diff --git a/fs/notify/group.c b/fs/notify/group.c +index fb89c351295d..460ad19c2570 100644 +--- a/fs/notify/group.c ++++ b/fs/notify/group.c +@@ -100,6 +100,7 @@ void fsnotify_get_group(struct fsnotify_group *group) + { + refcount_inc(&group->refcnt); + } ++EXPORT_SYMBOL_GPL(fsnotify_get_group); + + /* + * Drop a reference to a group. Free it if it's through. +diff --git a/fs/open.c b/fs/open.c +index e0df1536eb69..81b2d7c83add 100644 +--- a/fs/open.c ++++ b/fs/open.c +@@ -65,6 +65,7 @@ int do_truncate(struct user_namespace *mnt_userns, struct dentry *dentry, + inode_unlock(dentry->d_inode); + return ret; + } ++EXPORT_SYMBOL_GPL(do_truncate); + + long vfs_truncate(const struct path *path, loff_t length) + { +diff --git a/fs/read_write.c b/fs/read_write.c +index af057c57bdc6..76017f8331fb 100644 +--- a/fs/read_write.c ++++ b/fs/read_write.c +@@ -492,6 +492,7 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) + inc_syscr(current); + return ret; + } ++EXPORT_SYMBOL_GPL(vfs_read); + + static ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos) + { +@@ -602,6 +603,7 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_ + file_end_write(file); + return ret; + } ++EXPORT_SYMBOL_GPL(vfs_write); + + /* file_ppos returns &file->f_pos or NULL if file is stream */ + static inline loff_t *file_ppos(struct file *file) +diff --git a/fs/splice.c b/fs/splice.c +index 3e6ba363b777..7c1be373eb7c 100644 +--- a/fs/splice.c ++++ b/fs/splice.c +@@ -766,6 +766,7 @@ long do_splice_from(struct pipe_inode_info *pipe, struct file *out, + return warn_unsupported(out, "write"); + return out->f_op->splice_write(pipe, out, ppos, len, flags); + } ++EXPORT_SYMBOL_GPL(do_splice_from); + + /* + * Attempt to initiate a splice from a file to a pipe. +@@ -795,6 +796,7 @@ long do_splice_to(struct file *in, loff_t *ppos, + return warn_unsupported(in, "read"); + return in->f_op->splice_read(in, ppos, pipe, len, flags); + } ++EXPORT_SYMBOL_GPL(do_splice_to); + + /** + * splice_direct_to_actor - splices data directly between two non-pipes +diff --git a/fs/xattr.c b/fs/xattr.c +index 5c8c5175b385..ff7e9ff774b7 100644 +--- a/fs/xattr.c ++++ b/fs/xattr.c +@@ -384,6 +384,7 @@ vfs_getxattr_alloc(struct user_namespace *mnt_userns, struct dentry *dentry, + *xattr_value = value; + return error; + } ++EXPORT_SYMBOL_GPL(vfs_getxattr_alloc); + + ssize_t + __vfs_getxattr(struct dentry *dentry, struct inode *inode, const char *name, +diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c +index ce380d0abdf0..409c7d1a6803 100644 +--- a/kernel/locking/lockdep.c ++++ b/kernel/locking/lockdep.c +@@ -208,6 +208,7 @@ inline struct lock_class *lockdep_hlock_class(struct held_lock *hlock) + */ + return lock_classes + class_idx; + } ++EXPORT_SYMBOL_GPL(lockdep_hlock_class); + #define hlock_class(hlock) lockdep_hlock_class(hlock) + + #ifdef CONFIG_LOCK_STAT +diff --git a/kernel/task_work.c b/kernel/task_work.c +index 1698fbe6f0e1..081b05acadf8 100644 +--- a/kernel/task_work.c ++++ b/kernel/task_work.c +@@ -167,3 +167,4 @@ void task_work_run(void) + } while (work); + } + } ++EXPORT_SYMBOL_GPL(task_work_run); +diff --git a/security/security.c b/security/security.c +index da631339e969..894203de3bcb 100644 +--- a/security/security.c ++++ b/security/security.c +@@ -1160,6 +1160,7 @@ int security_path_rmdir(const struct path *dir, struct dentry *dentry) + return 0; + return call_int_hook(path_rmdir, 0, dir, dentry); + } ++EXPORT_SYMBOL_GPL(security_path_rmdir); + + int security_path_unlink(const struct path *dir, struct dentry *dentry) + { +@@ -1176,6 +1177,7 @@ int security_path_symlink(const struct path *dir, struct dentry *dentry, + return 0; + return call_int_hook(path_symlink, 0, dir, dentry, old_name); + } ++EXPORT_SYMBOL_GPL(security_path_symlink); + + int security_path_link(struct dentry *old_dentry, const struct path *new_dir, + struct dentry *new_dentry) +@@ -1184,6 +1186,7 @@ int security_path_link(struct dentry *old_dentry, const struct path *new_dir, + return 0; + return call_int_hook(path_link, 0, old_dentry, new_dir, new_dentry); + } ++EXPORT_SYMBOL_GPL(security_path_link); + + int security_path_rename(const struct path *old_dir, struct dentry *old_dentry, + const struct path *new_dir, struct dentry *new_dentry, +@@ -1211,6 +1214,7 @@ int security_path_truncate(const struct path *path) + return 0; + return call_int_hook(path_truncate, 0, path); + } ++EXPORT_SYMBOL_GPL(security_path_truncate); + + int security_path_chmod(const struct path *path, umode_t mode) + { +@@ -1218,6 +1222,7 @@ int security_path_chmod(const struct path *path, umode_t mode) + return 0; + return call_int_hook(path_chmod, 0, path, mode); + } ++EXPORT_SYMBOL_GPL(security_path_chmod); + + int security_path_chown(const struct path *path, kuid_t uid, kgid_t gid) + { +@@ -1225,6 +1230,7 @@ int security_path_chown(const struct path *path, kuid_t uid, kgid_t gid) + return 0; + return call_int_hook(path_chown, 0, path, uid, gid); + } ++EXPORT_SYMBOL_GPL(security_path_chown); + + int security_path_chroot(const struct path *path) + { +@@ -1325,6 +1331,7 @@ int security_inode_permission(struct inode *inode, int mask) + return 0; + return call_int_hook(inode_permission, 0, inode, mask); + } ++EXPORT_SYMBOL_GPL(security_inode_permission); + + int security_inode_setattr(struct dentry *dentry, struct iattr *attr) + { +@@ -1522,6 +1529,7 @@ int security_file_permission(struct file *file, int mask) + + return fsnotify_perm(file, mask); + } ++EXPORT_SYMBOL_GPL(security_file_permission); + + int security_file_alloc(struct file *file) + { diff --git a/kernel/tools/perf/files/patches/aufs5/aufs5.15.36-20220509.patch b/kernel/tools/perf/files/patches/aufs5/aufs5.15.36-20220509.patch new file mode 100644 index 0000000000..034b926d94 --- /dev/null +++ b/kernel/tools/perf/files/patches/aufs5/aufs5.15.36-20220509.patch @@ -0,0 +1,38475 @@ +diff -Naur null/Documentation/ABI/testing/debugfs-aufs linux-5.15.36/Documentation/ABI/testing/debugfs-aufs +--- /dev/null ++++ linux-5.15.36/Documentation/ABI/testing/debugfs-aufs 2022-05-10 16:51:39.862744220 +0300 +@@ -0,0 +1,55 @@ ++What: /debug/aufs/si_/ ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ Under /debug/aufs, a directory named si_ is created ++ per aufs mount, where is a unique id generated ++ internally. ++ ++What: /debug/aufs/si_/plink ++Date: Apr 2013 ++Contact: J. R. Okajima ++Description: ++ It has three lines and shows the information about the ++ pseudo-link. The first line is a single number ++ representing a number of buckets. The second line is a ++ number of pseudo-links per buckets (separated by a ++ blank). The last line is a single number representing a ++ total number of psedo-links. ++ When the aufs mount option 'noplink' is specified, it ++ will show "1\n0\n0\n". ++ ++What: /debug/aufs/si_/xib ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ It shows the consumed blocks by xib (External Inode Number ++ Bitmap), its block size and file size. ++ When the aufs mount option 'noxino' is specified, it ++ will be empty. About XINO files, see the aufs manual. ++ ++What: /debug/aufs/si_/xi ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ It shows the consumed blocks by xino (External Inode Number ++ Translation Table), its link count, block size and file ++ size. ++ Due to the file size limit, there may exist multiple ++ xino files per branch. In this case, "-N" is added to ++ the filename and it corresponds to the index of the ++ internal xino array. "-0" is omitted. ++ When the aufs mount option 'noxino' is specified, Those ++ entries won't exist. About XINO files, see the aufs ++ manual. ++ ++What: /debug/aufs/si_/xigen ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ It shows the consumed blocks by xigen (External Inode ++ Generation Table), its block size and file size. ++ If CONFIG_AUFS_EXPORT is disabled, this entry will not ++ be created. ++ When the aufs mount option 'noxino' is specified, it ++ will be empty. About XINO files, see the aufs manual. +diff -Naur null/Documentation/ABI/testing/sysfs-aufs linux-5.15.36/Documentation/ABI/testing/sysfs-aufs +--- /dev/null ++++ linux-5.15.36/Documentation/ABI/testing/sysfs-aufs 2022-05-10 16:51:39.863744220 +0300 +@@ -0,0 +1,31 @@ ++What: /sys/fs/aufs/si_/ ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ Under /sys/fs/aufs, a directory named si_ is created ++ per aufs mount, where is a unique id generated ++ internally. ++ ++What: /sys/fs/aufs/si_/br ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ It shows the abolute path of a member directory (which ++ is called branch) in aufs, and its permission. ++ ++What: /sys/fs/aufs/si_/brid ++Date: July 2013 ++Contact: J. R. Okajima ++Description: ++ It shows the id of a member directory (which is called ++ branch) in aufs. ++ ++What: /sys/fs/aufs/si_/xi_path ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ It shows the abolute path of XINO (External Inode Number ++ Bitmap, Translation Table and Generation Table) file ++ even if it is the default path. ++ When the aufs mount option 'noxino' is specified, it ++ will be empty. About XINO files, see the aufs manual. +diff -Naur null/Documentation/filesystems/aufs/design/01intro.txt linux-5.15.36/Documentation/filesystems/aufs/design/01intro.txt +--- /dev/null ++++ linux-5.15.36/Documentation/filesystems/aufs/design/01intro.txt 2022-05-10 16:51:39.863744220 +0300 +@@ -0,0 +1,171 @@ ++ ++# Copyright (C) 2005-2021 Junjiro R. Okajima ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++Introduction ++---------------------------------------- ++ ++aufs [ei ju: ef es] | /ey-yoo-ef-es/ | [a u f s] ++1. abbrev. for "advanced multi-layered unification filesystem". ++2. abbrev. for "another unionfs". ++3. abbrev. for "auf das" in German which means "on the" in English. ++ Ex. "Butter aufs Brot"(G) means "butter onto bread"(E). ++ But "Filesystem aufs Filesystem" is hard to understand. ++4. abbrev. for "African Urban Fashion Show". ++ ++AUFS is a filesystem with features: ++- multi layered stackable unification filesystem, the member directory ++ is called as a branch. ++- branch permission and attribute, 'readonly', 'real-readonly', ++ 'readwrite', 'whiteout-able', 'link-able whiteout', etc. and their ++ combination. ++- internal "file copy-on-write". ++- logical deletion, whiteout. ++- dynamic branch manipulation, adding, deleting and changing permission. ++- allow bypassing aufs, user's direct branch access. ++- external inode number translation table and bitmap which maintains the ++ persistent aufs inode number. ++- seekable directory, including NFS readdir. ++- file mapping, mmap and sharing pages. ++- pseudo-link, hardlink over branches. ++- loopback mounted filesystem as a branch. ++- several policies to select one among multiple writable branches. ++- revert a single systemcall when an error occurs in aufs. ++- and more... ++ ++ ++Multi Layered Stackable Unification Filesystem ++---------------------------------------------------------------------- ++Most people already knows what it is. ++It is a filesystem which unifies several directories and provides a ++merged single directory. When users access a file, the access will be ++passed/re-directed/converted (sorry, I am not sure which English word is ++correct) to the real file on the member filesystem. The member ++filesystem is called 'lower filesystem' or 'branch' and has a mode ++'readonly' and 'readwrite.' And the deletion for a file on the lower ++readonly branch is handled by creating 'whiteout' on the upper writable ++branch. ++ ++On LKML, there have been discussions about UnionMount (Jan Blunck, ++Bharata B Rao and Valerie Aurora) and Unionfs (Erez Zadok). They took ++different approaches to implement the merged-view. ++The former tries putting it into VFS, and the latter implements as a ++separate filesystem. ++(If I misunderstand about these implementations, please let me know and ++I shall correct it. Because it is a long time ago when I read their ++source files last time). ++ ++UnionMount's approach will be able to small, but may be hard to share ++branches between several UnionMount since the whiteout in it is ++implemented in the inode on branch filesystem and always ++shared. According to Bharata's post, readdir does not seems to be ++finished yet. ++There are several missing features known in this implementations such as ++- for users, the inode number may change silently. eg. copy-up. ++- link(2) may break by copy-up. ++- read(2) may get an obsoleted filedata (fstat(2) too). ++- fcntl(F_SETLK) may be broken by copy-up. ++- unnecessary copy-up may happen, for example mmap(MAP_PRIVATE) after ++ open(O_RDWR). ++ ++In linux-3.18, "overlay" filesystem (formerly known as "overlayfs") was ++merged into mainline. This is another implementation of UnionMount as a ++separated filesystem. All the limitations and known problems which ++UnionMount are equally inherited to "overlay" filesystem. ++ ++Unionfs has a longer history. When I started implementing a stackable ++filesystem (Aug 2005), it already existed. It has virtual super_block, ++inode, dentry and file objects and they have an array pointing lower ++same kind objects. After contributing many patches for Unionfs, I ++re-started my project AUFS (Jun 2006). ++ ++In AUFS, the structure of filesystem resembles to Unionfs, but I ++implemented my own ideas, approaches and enhancements and it became ++totally different one. ++ ++Comparing DM snapshot and fs based implementation ++- the number of bytes to be copied between devices is much smaller. ++- the type of filesystem must be one and only. ++- the fs must be writable, no readonly fs, even for the lower original ++ device. so the compression fs will not be usable. but if we use ++ loopback mount, we may address this issue. ++ for instance, ++ mount /cdrom/squashfs.img /sq ++ losetup /sq/ext2.img ++ losetup /somewhere/cow ++ dmsetup "snapshot /dev/loop0 /dev/loop1 ..." ++- it will be difficult (or needs more operations) to extract the ++ difference between the original device and COW. ++- DM snapshot-merge may help a lot when users try merging. in the ++ fs-layer union, users will use rsync(1). ++ ++You may want to read my old paper "Filesystems in LiveCD" ++(http://aufs.sourceforge.net/aufs2/report/sq/sq.pdf). ++ ++ ++Several characters/aspects/persona of aufs ++---------------------------------------------------------------------- ++ ++Aufs has several characters, aspects or persona. ++1. a filesystem, callee of VFS helper ++2. sub-VFS, caller of VFS helper for branches ++3. a virtual filesystem which maintains persistent inode number ++4. reader/writer of files on branches such like an application ++ ++1. Callee of VFS Helper ++As an ordinary linux filesystem, aufs is a callee of VFS. For instance, ++unlink(2) from an application reaches sys_unlink() kernel function and ++then vfs_unlink() is called. vfs_unlink() is one of VFS helper and it ++calls filesystem specific unlink operation. Actually aufs implements the ++unlink operation but it behaves like a redirector. ++ ++2. Caller of VFS Helper for Branches ++aufs_unlink() passes the unlink request to the branch filesystem as if ++it were called from VFS. So the called unlink operation of the branch ++filesystem acts as usual. As a caller of VFS helper, aufs should handle ++every necessary pre/post operation for the branch filesystem. ++- acquire the lock for the parent dir on a branch ++- lookup in a branch ++- revalidate dentry on a branch ++- mnt_want_write() for a branch ++- vfs_unlink() for a branch ++- mnt_drop_write() for a branch ++- release the lock on a branch ++ ++3. Persistent Inode Number ++One of the most important issue for a filesystem is to maintain inode ++numbers. This is particularly important to support exporting a ++filesystem via NFS. Aufs is a virtual filesystem which doesn't have a ++backend block device for its own. But some storage is necessary to ++keep and maintain the inode numbers. It may be a large space and may not ++suit to keep in memory. Aufs rents some space from its first writable ++branch filesystem (by default) and creates file(s) on it. These files ++are created by aufs internally and removed soon (currently) keeping ++opened. ++Note: Because these files are removed, they are totally gone after ++ unmounting aufs. It means the inode numbers are not persistent ++ across unmount or reboot. I have a plan to make them really ++ persistent which will be important for aufs on NFS server. ++ ++4. Read/Write Files Internally (copy-on-write) ++Because a branch can be readonly, when you write a file on it, aufs will ++"copy-up" it to the upper writable branch internally. And then write the ++originally requested thing to the file. Generally kernel doesn't ++open/read/write file actively. In aufs, even a single write may cause a ++internal "file copy". This behaviour is very similar to cp(1) command. ++ ++Some people may think it is better to pass such work to user space ++helper, instead of doing in kernel space. Actually I am still thinking ++about it. But currently I have implemented it in kernel space. +diff -Naur null/Documentation/filesystems/aufs/design/02struct.txt linux-5.15.36/Documentation/filesystems/aufs/design/02struct.txt +--- /dev/null ++++ linux-5.15.36/Documentation/filesystems/aufs/design/02struct.txt 2022-05-10 16:51:39.863744220 +0300 +@@ -0,0 +1,258 @@ ++ ++# Copyright (C) 2005-2021 Junjiro R. Okajima ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++Basic Aufs Internal Structure ++ ++Superblock/Inode/Dentry/File Objects ++---------------------------------------------------------------------- ++As like an ordinary filesystem, aufs has its own ++superblock/inode/dentry/file objects. All these objects have a ++dynamically allocated array and store the same kind of pointers to the ++lower filesystem, branch. ++For example, when you build a union with one readwrite branch and one ++readonly, mounted /au, /rw and /ro respectively. ++- /au = /rw + /ro ++- /ro/fileA exists but /rw/fileA ++ ++Aufs lookup operation finds /ro/fileA and gets dentry for that. These ++pointers are stored in a aufs dentry. The array in aufs dentry will be, ++- [0] = NULL (because /rw/fileA doesn't exist) ++- [1] = /ro/fileA ++ ++This style of an array is essentially same to the aufs ++superblock/inode/dentry/file objects. ++ ++Because aufs supports manipulating branches, ie. add/delete/change ++branches dynamically, these objects has its own generation. When ++branches are changed, the generation in aufs superblock is ++incremented. And a generation in other object are compared when it is ++accessed. When a generation in other objects are obsoleted, aufs ++refreshes the internal array. ++ ++ ++Superblock ++---------------------------------------------------------------------- ++Additionally aufs superblock has some data for policies to select one ++among multiple writable branches, XIB files, pseudo-links and kobject. ++See below in detail. ++About the policies which supports copy-down a directory, see ++wbr_policy.txt too. ++ ++ ++Branch and XINO(External Inode Number Translation Table) ++---------------------------------------------------------------------- ++Every branch has its own xino (external inode number translation table) ++file. The xino file is created and unlinked by aufs internally. When two ++members of a union exist on the same filesystem, they share the single ++xino file. ++The struct of a xino file is simple, just a sequence of aufs inode ++numbers which is indexed by the lower inode number. ++In the above sample, assume the inode number of /ro/fileA is i111 and ++aufs assigns the inode number i999 for fileA. Then aufs writes 999 as ++4(8) bytes at 111 * 4(8) bytes offset in the xino file. ++ ++When the inode numbers are not contiguous, the xino file will be sparse ++which has a hole in it and doesn't consume as much disk space as it ++might appear. If your branch filesystem consumes disk space for such ++holes, then you should specify 'xino=' option at mounting aufs. ++ ++Aufs has a mount option to free the disk blocks for such holes in XINO ++files on tmpfs or ramdisk. But it is not so effective actually. If you ++meet a problem of disk shortage due to XINO files, then you should try ++"tmpfs-ino.patch" (and "vfs-ino.patch" too) in aufs4-standalone.git. ++The patch localizes the assignment inumbers per tmpfs-mount and avoid ++the holes in XINO files. ++ ++Also a writable branch has three kinds of "whiteout bases". All these ++are existed when the branch is joined to aufs, and their names are ++whiteout-ed doubly, so that users will never see their names in aufs ++hierarchy. ++1. a regular file which will be hardlinked to all whiteouts. ++2. a directory to store a pseudo-link. ++3. a directory to store an "orphan"-ed file temporary. ++ ++1. Whiteout Base ++ When you remove a file on a readonly branch, aufs handles it as a ++ logical deletion and creates a whiteout on the upper writable branch ++ as a hardlink of this file in order not to consume inode on the ++ writable branch. ++2. Pseudo-link Dir ++ See below, Pseudo-link. ++3. Step-Parent Dir ++ When "fileC" exists on the lower readonly branch only and it is ++ opened and removed with its parent dir, and then user writes ++ something into it, then aufs copies-up fileC to this ++ directory. Because there is no other dir to store fileC. After ++ creating a file under this dir, the file is unlinked. ++ ++Because aufs supports manipulating branches, ie. add/delete/change ++dynamically, a branch has its own id. When the branch order changes, ++aufs finds the new index by searching the branch id. ++ ++ ++Pseudo-link ++---------------------------------------------------------------------- ++Assume "fileA" exists on the lower readonly branch only and it is ++hardlinked to "fileB" on the branch. When you write something to fileA, ++aufs copies-up it to the upper writable branch. Additionally aufs ++creates a hardlink under the Pseudo-link Directory of the writable ++branch. The inode of a pseudo-link is kept in aufs super_block as a ++simple list. If fileB is read after unlinking fileA, aufs returns ++filedata from the pseudo-link instead of the lower readonly ++branch. Because the pseudo-link is based upon the inode, to keep the ++inode number by xino (see above) is essentially necessary. ++ ++All the hardlinks under the Pseudo-link Directory of the writable branch ++should be restored in a proper location later. Aufs provides a utility ++to do this. The userspace helpers executed at remounting and unmounting ++aufs by default. ++During this utility is running, it puts aufs into the pseudo-link ++maintenance mode. In this mode, only the process which began the ++maintenance mode (and its child processes) is allowed to operate in ++aufs. Some other processes which are not related to the pseudo-link will ++be allowed to run too, but the rest have to return an error or wait ++until the maintenance mode ends. If a process already acquires an inode ++mutex (in VFS), it has to return an error. ++ ++ ++XIB(external inode number bitmap) ++---------------------------------------------------------------------- ++Addition to the xino file per a branch, aufs has an external inode number ++bitmap in a superblock object. It is also an internal file such like a ++xino file. ++It is a simple bitmap to mark whether the aufs inode number is in-use or ++not. ++To reduce the file I/O, aufs prepares a single memory page to cache xib. ++ ++As well as XINO files, aufs has a feature to truncate/refresh XIB to ++reduce the number of consumed disk blocks for these files. ++ ++ ++Virtual or Vertical Dir, and Readdir in Userspace ++---------------------------------------------------------------------- ++In order to support multiple layers (branches), aufs readdir operation ++constructs a virtual dir block on memory. For readdir, aufs calls ++vfs_readdir() internally for each dir on branches, merges their entries ++with eliminating the whiteout-ed ones, and sets it to file (dir) ++object. So the file object has its entry list until it is closed. The ++entry list will be updated when the file position is zero and becomes ++obsoleted. This decision is made in aufs automatically. ++ ++The dynamically allocated memory block for the name of entries has a ++unit of 512 bytes (by default) and stores the names contiguously (no ++padding). Another block for each entry is handled by kmem_cache too. ++During building dir blocks, aufs creates hash list and judging whether ++the entry is whiteouted by its upper branch or already listed. ++The merged result is cached in the corresponding inode object and ++maintained by a customizable life-time option. ++ ++Some people may call it can be a security hole or invite DoS attack ++since the opened and once readdir-ed dir (file object) holds its entry ++list and becomes a pressure for system memory. But I'd say it is similar ++to files under /proc or /sys. The virtual files in them also holds a ++memory page (generally) while they are opened. When an idea to reduce ++memory for them is introduced, it will be applied to aufs too. ++For those who really hate this situation, I've developed readdir(3) ++library which operates this merging in userspace. You just need to set ++LD_PRELOAD environment variable, and aufs will not consume no memory in ++kernel space for readdir(3). ++ ++ ++Workqueue ++---------------------------------------------------------------------- ++Aufs sometimes requires privilege access to a branch. For instance, ++in copy-up/down operation. When a user process is going to make changes ++to a file which exists in the lower readonly branch only, and the mode ++of one of ancestor directories may not be writable by a user ++process. Here aufs copy-up the file with its ancestors and they may ++require privilege to set its owner/group/mode/etc. ++This is a typical case of a application character of aufs (see ++Introduction). ++ ++Aufs uses workqueue synchronously for this case. It creates its own ++workqueue. The workqueue is a kernel thread and has privilege. Aufs ++passes the request to call mkdir or write (for example), and wait for ++its completion. This approach solves a problem of a signal handler ++simply. ++If aufs didn't adopt the workqueue and changed the privilege of the ++process, then the process may receive the unexpected SIGXFSZ or other ++signals. ++ ++Also aufs uses the system global workqueue ("events" kernel thread) too ++for asynchronous tasks, such like handling inotify/fsnotify, re-creating a ++whiteout base and etc. This is unrelated to a privilege. ++Most of aufs operation tries acquiring a rw_semaphore for aufs ++superblock at the beginning, at the same time waits for the completion ++of all queued asynchronous tasks. ++ ++ ++Whiteout ++---------------------------------------------------------------------- ++The whiteout in aufs is very similar to Unionfs's. That is represented ++by its filename. UnionMount takes an approach of a file mode, but I am ++afraid several utilities (find(1) or something) will have to support it. ++ ++Basically the whiteout represents "logical deletion" which stops aufs to ++lookup further, but also it represents "dir is opaque" which also stop ++further lookup. ++ ++In aufs, rmdir(2) and rename(2) for dir uses whiteout alternatively. ++In order to make several functions in a single systemcall to be ++revertible, aufs adopts an approach to rename a directory to a temporary ++unique whiteouted name. ++For example, in rename(2) dir where the target dir already existed, aufs ++renames the target dir to a temporary unique whiteouted name before the ++actual rename on a branch, and then handles other actions (make it opaque, ++update the attributes, etc). If an error happens in these actions, aufs ++simply renames the whiteouted name back and returns an error. If all are ++succeeded, aufs registers a function to remove the whiteouted unique ++temporary name completely and asynchronously to the system global ++workqueue. ++ ++ ++Copy-up ++---------------------------------------------------------------------- ++It is a well-known feature or concept. ++When user modifies a file on a readonly branch, aufs operate "copy-up" ++internally and makes change to the new file on the upper writable branch. ++When the trigger systemcall does not update the timestamps of the parent ++dir, aufs reverts it after copy-up. ++ ++ ++Move-down (aufs3.9 and later) ++---------------------------------------------------------------------- ++"Copy-up" is one of the essential feature in aufs. It copies a file from ++the lower readonly branch to the upper writable branch when a user ++changes something about the file. ++"Move-down" is an opposite action of copy-up. Basically this action is ++ran manually instead of automatically and internally. ++For desgin and implementation, aufs has to consider these issues. ++- whiteout for the file may exist on the lower branch. ++- ancestor directories may not exist on the lower branch. ++- diropq for the ancestor directories may exist on the upper branch. ++- free space on the lower branch will reduce. ++- another access to the file may happen during moving-down, including ++ UDBA (see "Revalidate Dentry and UDBA"). ++- the file should not be hard-linked nor pseudo-linked. they should be ++ handled by auplink utility later. ++ ++Sometimes users want to move-down a file from the upper writable branch ++to the lower readonly or writable branch. For instance, ++- the free space of the upper writable branch is going to run out. ++- create a new intermediate branch between the upper and lower branch. ++- etc. ++ ++For this purpose, use "aumvdown" command in aufs-util.git. +diff -Naur null/Documentation/filesystems/aufs/design/03atomic_open.txt linux-5.15.36/Documentation/filesystems/aufs/design/03atomic_open.txt +--- /dev/null ++++ linux-5.15.36/Documentation/filesystems/aufs/design/03atomic_open.txt 2022-05-10 16:51:39.863744220 +0300 +@@ -0,0 +1,85 @@ ++ ++# Copyright (C) 2015-2021 Junjiro R. Okajima ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++Support for a branch who has its ->atomic_open() ++---------------------------------------------------------------------- ++The filesystems who implement its ->atomic_open() are not majority. For ++example NFSv4 does, and aufs should call NFSv4 ->atomic_open, ++particularly for open(O_CREAT|O_EXCL, 0400) case. Other than ++->atomic_open(), NFSv4 returns an error for this open(2). While I am not ++sure whether all filesystems who have ->atomic_open() behave like this, ++but NFSv4 surely returns the error. ++ ++In order to support ->atomic_open() for aufs, there are a few ++approaches. ++ ++A. Introduce aufs_atomic_open() ++ - calls one of VFS:do_last(), lookup_open() or atomic_open() for ++ branch fs. ++B. Introduce aufs_atomic_open() calling create, open and chmod. this is ++ an aufs user Pip Cet's approach ++ - calls aufs_create(), VFS finish_open() and notify_change(). ++ - pass fake-mode to finish_open(), and then correct the mode by ++ notify_change(). ++C. Extend aufs_open() to call branch fs's ->atomic_open() ++ - no aufs_atomic_open(). ++ - aufs_lookup() registers the TID to an aufs internal object. ++ - aufs_create() does nothing when the matching TID is registered, but ++ registers the mode. ++ - aufs_open() calls branch fs's ->atomic_open() when the matching ++ TID is registered. ++D. Extend aufs_open() to re-try branch fs's ->open() with superuser's ++ credential ++ - no aufs_atomic_open(). ++ - aufs_create() registers the TID to an internal object. this info ++ represents "this process created this file just now." ++ - when aufs gets EACCES from branch fs's ->open(), then confirm the ++ registered TID and re-try open() with superuser's credential. ++ ++Pros and cons for each approach. ++ ++A. ++ - straightforward but highly depends upon VFS internal. ++ - the atomic behavaiour is kept. ++ - some of parameters such as nameidata are hard to reproduce for ++ branch fs. ++ - large overhead. ++B. ++ - easy to implement. ++ - the atomic behavaiour is lost. ++C. ++ - the atomic behavaiour is kept. ++ - dirty and tricky. ++ - VFS checks whether the file is created correctly after calling ++ ->create(), which means this approach doesn't work. ++D. ++ - easy to implement. ++ - the atomic behavaiour is lost. ++ - to open a file with superuser's credential and give it to a user ++ process is a bad idea, since the file object keeps the credential ++ in it. It may affect LSM or something. This approach doesn't work ++ either. ++ ++The approach A is ideal, but it hard to implement. So here is a ++variation of A, which is to be implemented. ++ ++A-1. Introduce aufs_atomic_open() ++ - calls branch fs ->atomic_open() if exists. otherwise calls ++ vfs_create() and finish_open(). ++ - the demerit is that the several checks after branch fs ++ ->atomic_open() are lost. in the ordinary case, the checks are ++ done by VFS:do_last(), lookup_open() and atomic_open(). some can ++ be implemented in aufs, but not all I am afraid. +diff -Naur null/Documentation/filesystems/aufs/design/03lookup.txt linux-5.15.36/Documentation/filesystems/aufs/design/03lookup.txt +--- /dev/null ++++ linux-5.15.36/Documentation/filesystems/aufs/design/03lookup.txt 2022-05-10 16:51:39.864744220 +0300 +@@ -0,0 +1,113 @@ ++ ++# Copyright (C) 2005-2021 Junjiro R. Okajima ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++Lookup in a Branch ++---------------------------------------------------------------------- ++Since aufs has a character of sub-VFS (see Introduction), it operates ++lookup for branches as VFS does. It may be a heavy work. But almost all ++lookup operation in aufs is the simplest case, ie. lookup only an entry ++directly connected to its parent. Digging down the directory hierarchy ++is unnecessary. VFS has a function lookup_one_len() for that use, and ++aufs calls it. ++ ++When a branch is a remote filesystem, aufs basically relies upon its ++->d_revalidate(), also aufs forces the hardest revalidate tests for ++them. ++For d_revalidate, aufs implements three levels of revalidate tests. See ++"Revalidate Dentry and UDBA" in detail. ++ ++ ++Test Only the Highest One for the Directory Permission (dirperm1 option) ++---------------------------------------------------------------------- ++Let's try case study. ++- aufs has two branches, upper readwrite and lower readonly. ++ /au = /rw + /ro ++- "dirA" exists under /ro, but /rw. and its mode is 0700. ++- user invoked "chmod a+rx /au/dirA" ++- the internal copy-up is activated and "/rw/dirA" is created and its ++ permission bits are set to world readable. ++- then "/au/dirA" becomes world readable? ++ ++In this case, /ro/dirA is still 0700 since it exists in readonly branch, ++or it may be a natively readonly filesystem. If aufs respects the lower ++branch, it should not respond readdir request from other users. But user ++allowed it by chmod. Should really aufs rejects showing the entries ++under /ro/dirA? ++ ++To be honest, I don't have a good solution for this case. So aufs ++implements 'dirperm1' and 'nodirperm1' mount options, and leave it to ++users. ++When dirperm1 is specified, aufs checks only the highest one for the ++directory permission, and shows the entries. Otherwise, as usual, checks ++every dir existing on all branches and rejects the request. ++ ++As a side effect, dirperm1 option improves the performance of aufs ++because the number of permission check is reduced when the number of ++branch is many. ++ ++ ++Revalidate Dentry and UDBA (User's Direct Branch Access) ++---------------------------------------------------------------------- ++Generally VFS helpers re-validate a dentry as a part of lookup. ++0. digging down the directory hierarchy. ++1. lock the parent dir by its i_mutex. ++2. lookup the final (child) entry. ++3. revalidate it. ++4. call the actual operation (create, unlink, etc.) ++5. unlock the parent dir ++ ++If the filesystem implements its ->d_revalidate() (step 3), then it is ++called. Actually aufs implements it and checks the dentry on a branch is ++still valid. ++But it is not enough. Because aufs has to release the lock for the ++parent dir on a branch at the end of ->lookup() (step 2) and ++->d_revalidate() (step 3) while the i_mutex of the aufs dir is still ++held by VFS. ++If the file on a branch is changed directly, eg. bypassing aufs, after ++aufs released the lock, then the subsequent operation may cause ++something unpleasant result. ++ ++This situation is a result of VFS architecture, ->lookup() and ++->d_revalidate() is separated. But I never say it is wrong. It is a good ++design from VFS's point of view. It is just not suitable for sub-VFS ++character in aufs. ++ ++Aufs supports such case by three level of revalidation which is ++selectable by user. ++1. Simple Revalidate ++ Addition to the native flow in VFS's, confirm the child-parent ++ relationship on the branch just after locking the parent dir on the ++ branch in the "actual operation" (step 4). When this validation ++ fails, aufs returns EBUSY. ->d_revalidate() (step 3) in aufs still ++ checks the validation of the dentry on branches. ++2. Monitor Changes Internally by Inotify/Fsnotify ++ Addition to above, in the "actual operation" (step 4) aufs re-lookup ++ the dentry on the branch, and returns EBUSY if it finds different ++ dentry. ++ Additionally, aufs sets the inotify/fsnotify watch for every dir on branches ++ during it is in cache. When the event is notified, aufs registers a ++ function to kernel 'events' thread by schedule_work(). And the ++ function sets some special status to the cached aufs dentry and inode ++ private data. If they are not cached, then aufs has nothing to ++ do. When the same file is accessed through aufs (step 0-3) later, ++ aufs will detect the status and refresh all necessary data. ++ In this mode, aufs has to ignore the event which is fired by aufs ++ itself. ++3. No Extra Validation ++ This is the simplest test and doesn't add any additional revalidation ++ test, and skip the revalidation in step 4. It is useful and improves ++ aufs performance when system surely hide the aufs branches from user, ++ by over-mounting something (or another method). +diff -Naur null/Documentation/filesystems/aufs/design/04branch.txt linux-5.15.36/Documentation/filesystems/aufs/design/04branch.txt +--- /dev/null ++++ linux-5.15.36/Documentation/filesystems/aufs/design/04branch.txt 2022-05-10 16:51:39.864744220 +0300 +@@ -0,0 +1,74 @@ ++ ++# Copyright (C) 2005-2021 Junjiro R. Okajima ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++Branch Manipulation ++ ++Since aufs supports dynamic branch manipulation, ie. add/remove a branch ++and changing its permission/attribute, there are a lot of works to do. ++ ++ ++Add a Branch ++---------------------------------------------------------------------- ++o Confirm the adding dir exists outside of aufs, including loopback ++ mount, and its various attributes. ++o Initialize the xino file and whiteout bases if necessary. ++ See struct.txt. ++ ++o Check the owner/group/mode of the directory ++ When the owner/group/mode of the adding directory differs from the ++ existing branch, aufs issues a warning because it may impose a ++ security risk. ++ For example, when a upper writable branch has a world writable empty ++ top directory, a malicious user can create any files on the writable ++ branch directly, like copy-up and modify manually. If something like ++ /etc/{passwd,shadow} exists on the lower readonly branch but the upper ++ writable branch, and the writable branch is world-writable, then a ++ malicious guy may create /etc/passwd on the writable branch directly ++ and the infected file will be valid in aufs. ++ I am afraid it can be a security issue, but aufs can do nothing except ++ producing a warning. ++ ++ ++Delete a Branch ++---------------------------------------------------------------------- ++o Confirm the deleting branch is not busy ++ To be general, there is one merit to adopt "remount" interface to ++ manipulate branches. It is to discard caches. At deleting a branch, ++ aufs checks the still cached (and connected) dentries and inodes. If ++ there are any, then they are all in-use. An inode without its ++ corresponding dentry can be alive alone (for example, inotify/fsnotify case). ++ ++ For the cached one, aufs checks whether the same named entry exists on ++ other branches. ++ If the cached one is a directory, because aufs provides a merged view ++ to users, as long as one dir is left on any branch aufs can show the ++ dir to users. In this case, the branch can be removed from aufs. ++ Otherwise aufs rejects deleting the branch. ++ ++ If any file on the deleting branch is opened by aufs, then aufs ++ rejects deleting. ++ ++ ++Modify the Permission of a Branch ++---------------------------------------------------------------------- ++o Re-initialize or remove the xino file and whiteout bases if necessary. ++ See struct.txt. ++ ++o rw --> ro: Confirm the modifying branch is not busy ++ Aufs rejects the request if any of these conditions are true. ++ - a file on the branch is mmap-ed. ++ - a regular file on the branch is opened for write and there is no ++ same named entry on the upper branch. +diff -Naur null/Documentation/filesystems/aufs/design/05wbr_policy.txt linux-5.15.36/Documentation/filesystems/aufs/design/05wbr_policy.txt +--- /dev/null ++++ linux-5.15.36/Documentation/filesystems/aufs/design/05wbr_policy.txt 2022-05-10 16:51:39.864744220 +0300 +@@ -0,0 +1,64 @@ ++ ++# Copyright (C) 2005-2021 Junjiro R. Okajima ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++Policies to Select One among Multiple Writable Branches ++---------------------------------------------------------------------- ++When the number of writable branch is more than one, aufs has to decide ++the target branch for file creation or copy-up. By default, the highest ++writable branch which has the parent (or ancestor) dir of the target ++file is chosen (top-down-parent policy). ++By user's request, aufs implements some other policies to select the ++writable branch, for file creation several policies, round-robin, ++most-free-space, and other policies. For copy-up, top-down-parent, ++bottom-up-parent, bottom-up and others. ++ ++As expected, the round-robin policy selects the branch in circular. When ++you have two writable branches and creates 10 new files, 5 files will be ++created for each branch. mkdir(2) systemcall is an exception. When you ++create 10 new directories, all will be created on the same branch. ++And the most-free-space policy selects the one which has most free ++space among the writable branches. The amount of free space will be ++checked by aufs internally, and users can specify its time interval. ++ ++The policies for copy-up is more simple, ++top-down-parent is equivalent to the same named on in create policy, ++bottom-up-parent selects the writable branch where the parent dir ++exists and the nearest upper one from the copyup-source, ++bottom-up selects the nearest upper writable branch from the ++copyup-source, regardless the existence of the parent dir. ++ ++There are some rules or exceptions to apply these policies. ++- If there is a readonly branch above the policy-selected branch and ++ the parent dir is marked as opaque (a variation of whiteout), or the ++ target (creating) file is whiteout-ed on the upper readonly branch, ++ then the result of the policy is ignored and the target file will be ++ created on the nearest upper writable branch than the readonly branch. ++- If there is a writable branch above the policy-selected branch and ++ the parent dir is marked as opaque or the target file is whiteouted ++ on the branch, then the result of the policy is ignored and the target ++ file will be created on the highest one among the upper writable ++ branches who has diropq or whiteout. In case of whiteout, aufs removes ++ it as usual. ++- link(2) and rename(2) systemcalls are exceptions in every policy. ++ They try selecting the branch where the source exists as possible ++ since copyup a large file will take long time. If it can't be, ++ ie. the branch where the source exists is readonly, then they will ++ follow the copyup policy. ++- There is an exception for rename(2) when the target exists. ++ If the rename target exists, aufs compares the index of the branches ++ where the source and the target exists and selects the higher ++ one. If the selected branch is readonly, then aufs follows the ++ copyup policy. +diff -Naur null/Documentation/filesystems/aufs/design/06dirren.dot linux-5.15.36/Documentation/filesystems/aufs/design/06dirren.dot +--- /dev/null ++++ linux-5.15.36/Documentation/filesystems/aufs/design/06dirren.dot 2022-05-10 16:51:39.864744220 +0300 +@@ -0,0 +1,31 @@ ++ ++// to view this graph, run dot(1) command in GRAPHVIZ. ++ ++digraph G { ++node [shape=box]; ++whinfo [label="detailed info file\n(lower_brid_root-hinum, h_inum, namelen, old name)"]; ++ ++node [shape=oval]; ++ ++aufs_rename -> whinfo [label="store/remove"]; ++ ++node [shape=oval]; ++inode_list [label="h_inum list in branch\ncache"]; ++ ++node [shape=box]; ++whinode [label="h_inum list file"]; ++ ++node [shape=oval]; ++brmgmt [label="br_add/del/mod/umount"]; ++ ++brmgmt -> inode_list [label="create/remove"]; ++brmgmt -> whinode [label="load/store"]; ++ ++inode_list -> whinode [style=dashed,dir=both]; ++ ++aufs_rename -> inode_list [label="add/del"]; ++ ++aufs_lookup -> inode_list [label="search"]; ++ ++aufs_lookup -> whinfo [label="load/remove"]; ++} +diff -Naur null/Documentation/filesystems/aufs/design/06dirren.txt linux-5.15.36/Documentation/filesystems/aufs/design/06dirren.txt +--- /dev/null ++++ linux-5.15.36/Documentation/filesystems/aufs/design/06dirren.txt 2022-05-10 16:51:39.864744220 +0300 +@@ -0,0 +1,102 @@ ++ ++# Copyright (C) 2017-2021 Junjiro R. Okajima ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++Special handling for renaming a directory (DIRREN) ++---------------------------------------------------------------------- ++First, let's assume we have a simple usecase. ++ ++- /u = /rw + /ro ++- /rw/dirA exists ++- /ro/dirA and /ro/dirA/file exist too ++- there is no dirB on both branches ++- a user issues rename("dirA", "dirB") ++ ++Now, what should aufs behave against this rename(2)? ++There are a few possible cases. ++ ++A. returns EROFS. ++ since dirA exists on a readonly branch which cannot be renamed. ++B. returns EXDEV. ++ it is possible to copy-up dirA (only the dir itself), but the child ++ entries ("file" in this case) should not be. it must be a bad ++ approach to copy-up recursively. ++C. returns a success. ++ even the branch /ro is readonly, aufs tries renaming it. Obviously it ++ is a violation of aufs' policy. ++D. construct an extra information which indicates that /ro/dirA should ++ be handled as the name of dirB. ++ overlayfs has a similar feature called REDIRECT. ++ ++Until now, aufs implements the case B only which returns EXDEV, and ++expects the userspace application behaves like mv(1) which tries ++issueing rename(2) recursively. ++ ++A new aufs feature called DIRREN is introduced which implements the case ++D. There are several "extra information" added. ++ ++1. detailed info per renamed directory ++ path: /rw/dirB/$AUFS_WH_DR_INFO_PFX. ++2. the inode-number list of directories on a branch ++ path: /rw/dirB/$AUFS_WH_DR_BRHINO ++ ++The filename of "detailed info per directory" represents the lower ++branch, and its format is ++- a type of the branch id ++ one of these. ++ + uuid (not implemented yet) ++ + fsid ++ + dev ++- the inode-number of the branch root dir ++ ++And it contains these info in a single regular file. ++- magic number ++- branch's inode-number of the logically renamed dir ++- the name of the before-renamed dir ++ ++The "detailed info per directory" file is created in aufs rename(2), and ++loaded in any lookup. ++The info is considered in lookup for the matching case only. Here ++"matching" means that the root of branch (in the info filename) is same ++to the current looking-up branch. After looking-up the before-renamed ++name, the inode-number is compared. And the matched dentry is used. ++ ++The "inode-number list of directories" is a regular file which contains ++simply the inode-numbers on the branch. The file is created or updated ++in removing the branch, and loaded in adding the branch. Its lifetime is ++equal to the branch. ++The list is refered in lookup, and when the current target inode is ++found in the list, the aufs tries loading the "detailed info per ++directory" and get the changed and valid name of the dir. ++ ++Theoretically these "extra informaiton" may be able to be put into XATTR ++in the dir inode. But aufs doesn't choose this way because ++1. XATTR may not be supported by the branch (or its configuration) ++2. XATTR may have its size limit. ++3. XATTR may be less easy to convert than a regular file, when the ++ format of the info is changed in the future. ++At the same time, I agree that the regular file approach is much slower ++than XATTR approach. So, in the future, aufs may take the XATTR or other ++better approach. ++ ++This DIRREN feature is enabled by aufs configuration, and is activated ++by a new mount option. ++ ++For the more complicated case, there is a work with UDBA option, which ++is to dected the direct access to the branches (by-passing aufs) and to ++maintain the cashes in aufs. Since a single cached aufs dentry may ++contains two names, before- and after-rename, the name comparision in ++UDBA handler may not work correctly. In this case, the behaviour will be ++equivalen to udba=reval case. +diff -Naur null/Documentation/filesystems/aufs/design/06fhsm.txt linux-5.15.36/Documentation/filesystems/aufs/design/06fhsm.txt +--- /dev/null ++++ linux-5.15.36/Documentation/filesystems/aufs/design/06fhsm.txt 2022-05-10 16:51:39.864744220 +0300 +@@ -0,0 +1,120 @@ ++ ++# Copyright (C) 2011-2021 Junjiro R. Okajima ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ ++ ++File-based Hierarchical Storage Management (FHSM) ++---------------------------------------------------------------------- ++Hierarchical Storage Management (or HSM) is a well-known feature in the ++storage world. Aufs provides this feature as file-based with multiple ++writable branches, based upon the principle of "Colder, the Lower". ++Here the word "colder" means that the less used files, and "lower" means ++that the position in the order of the stacked branches vertically. ++These multiple writable branches are prioritized, ie. the topmost one ++should be the fastest drive and be used heavily. ++ ++o Characters in aufs FHSM story ++- aufs itself and a new branch attribute. ++- a new ioctl interface to move-down and to establish a connection with ++ the daemon ("move-down" is a converse of "copy-up"). ++- userspace tool and daemon. ++ ++The userspace daemon establishes a connection with aufs and waits for ++the notification. The notified information is very similar to struct ++statfs containing the number of consumed blocks and inodes. ++When the consumed blocks/inodes of a branch exceeds the user-specified ++upper watermark, the daemon activates its move-down process until the ++consumed blocks/inodes reaches the user-specified lower watermark. ++ ++The actual move-down is done by aufs based upon the request from ++user-space since we need to maintain the inode number and the internal ++pointer arrays in aufs. ++ ++Currently aufs FHSM handles the regular files only. Additionally they ++must not be hard-linked nor pseudo-linked. ++ ++ ++o Cowork of aufs and the user-space daemon ++ During the userspace daemon established the connection, aufs sends a ++ small notification to it whenever aufs writes something into the ++ writable branch. But it may cost high since aufs issues statfs(2) ++ internally. So user can specify a new option to cache the ++ info. Actually the notification is controlled by these factors. ++ + the specified cache time. ++ + classified as "force" by aufs internally. ++ Until the specified time expires, aufs doesn't send the info ++ except the forced cases. When aufs decide forcing, the info is always ++ notified to userspace. ++ For example, the number of free inodes is generally large enough and ++ the shortage of it happens rarely. So aufs doesn't force the ++ notification when creating a new file, directory and others. This is ++ the typical case which aufs doesn't force. ++ When aufs writes the actual filedata and the files consumes any of new ++ blocks, the aufs forces notifying. ++ ++ ++o Interfaces in aufs ++- New branch attribute. ++ + fhsm ++ Specifies that the branch is managed by FHSM feature. In other word, ++ participant in the FHSM. ++ When nofhsm is set to the branch, it will not be the source/target ++ branch of the move-down operation. This attribute is set ++ independently from coo and moo attributes, and if you want full ++ FHSM, you should specify them as well. ++- New mount option. ++ + fhsm_sec ++ Specifies a second to suppress many less important info to be ++ notified. ++- New ioctl. ++ + AUFS_CTL_FHSM_FD ++ create a new file descriptor which userspace can read the notification ++ (a subset of struct statfs) from aufs. ++- Module parameter 'brs' ++ It has to be set to 1. Otherwise the new mount option 'fhsm' will not ++ be set. ++- mount helpers /sbin/mount.aufs and /sbin/umount.aufs ++ When there are two or more branches with fhsm attributes, ++ /sbin/mount.aufs invokes the user-space daemon and /sbin/umount.aufs ++ terminates it. As a result of remounting and branch-manipulation, the ++ number of branches with fhsm attribute can be one. In this case, ++ /sbin/mount.aufs will terminate the user-space daemon. ++ ++ ++Finally the operation is done as these steps in kernel-space. ++- make sure that, ++ + no one else is using the file. ++ + the file is not hard-linked. ++ + the file is not pseudo-linked. ++ + the file is a regular file. ++ + the parent dir is not opaqued. ++- find the target writable branch. ++- make sure the file is not whiteout-ed by the upper (than the target) ++ branch. ++- make the parent dir on the target branch. ++- mutex lock the inode on the branch. ++- unlink the whiteout on the target branch (if exists). ++- lookup and create the whiteout-ed temporary name on the target branch. ++- copy the file as the whiteout-ed temporary name on the target branch. ++- rename the whiteout-ed temporary name to the original name. ++- unlink the file on the source branch. ++- maintain the internal pointer array and the external inode number ++ table (XINO). ++- maintain the timestamps and other attributes of the parent dir and the ++ file. ++ ++And of course, in every step, an error may happen. So the operation ++should restore the original file state after an error happens. +diff -Naur null/Documentation/filesystems/aufs/design/06mmap.txt linux-5.15.36/Documentation/filesystems/aufs/design/06mmap.txt +--- /dev/null ++++ linux-5.15.36/Documentation/filesystems/aufs/design/06mmap.txt 2022-05-10 16:51:39.864744220 +0300 +@@ -0,0 +1,72 @@ ++ ++# Copyright (C) 2005-2021 Junjiro R. Okajima ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++mmap(2) -- File Memory Mapping ++---------------------------------------------------------------------- ++In aufs, the file-mapped pages are handled by a branch fs directly, no ++interaction with aufs. It means aufs_mmap() calls the branch fs's ++->mmap(). ++This approach is simple and good, but there is one problem. ++Under /proc, several entries show the mmapped files by its path (with ++device and inode number), and the printed path will be the path on the ++branch fs's instead of virtual aufs's. ++This is not a problem in most cases, but some utilities lsof(1) (and its ++user) may expect the path on aufs. ++ ++To address this issue, aufs adds a new member called vm_prfile in struct ++vm_area_struct (and struct vm_region). The original vm_file points to ++the file on the branch fs in order to handle everything correctly as ++usual. The new vm_prfile points to a virtual file in aufs, and the ++show-functions in procfs refers to vm_prfile if it is set. ++Also we need to maintain several other places where touching vm_file ++such like ++- fork()/clone() copies vma and the reference count of vm_file is ++ incremented. ++- merging vma maintains the ref count too. ++ ++This is not a good approach. It just fakes the printed path. But it ++leaves all behaviour around f_mapping unchanged. This is surely an ++advantage. ++Actually aufs had adopted another complicated approach which calls ++generic_file_mmap() and handles struct vm_operations_struct. In this ++approach, aufs met a hard problem and I could not solve it without ++switching the approach. ++ ++There may be one more another approach which is ++- bind-mount the branch-root onto the aufs-root internally ++- grab the new vfsmount (ie. struct mount) ++- lazy-umount the branch-root internally ++- in open(2) the aufs-file, open the branch-file with the hidden ++ vfsmount (instead of the original branch's vfsmount) ++- ideally this "bind-mount and lazy-umount" should be done atomically, ++ but it may be possible from userspace by the mount helper. ++ ++Adding the internal hidden vfsmount and using it in opening a file, the ++file path under /proc will be printed correctly. This approach looks ++smarter, but is not possible I am afraid. ++- aufs-root may be bind-mount later. when it happens, another hidden ++ vfsmount will be required. ++- it is hard to get the chance to bind-mount and lazy-umount ++ + in kernel-space, FS can have vfsmount in open(2) via ++ file->f_path, and aufs can know its vfsmount. But several locks are ++ already acquired, and if aufs tries to bind-mount and lazy-umount ++ here, then it may cause a deadlock. ++ + in user-space, bind-mount doesn't invoke the mount helper. ++- since /proc shows dev and ino, aufs has to give vma these info. it ++ means a new member vm_prinode will be necessary. this is essentially ++ equivalent to vm_prfile described above. ++ ++I have to give up this "looks-smater" approach. +diff -Naur null/Documentation/filesystems/aufs/design/06xattr.txt linux-5.15.36/Documentation/filesystems/aufs/design/06xattr.txt +--- /dev/null ++++ linux-5.15.36/Documentation/filesystems/aufs/design/06xattr.txt 2022-05-10 16:51:39.864744220 +0300 +@@ -0,0 +1,96 @@ ++ ++# Copyright (C) 2014-2021 Junjiro R. Okajima ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ ++ ++Listing XATTR/EA and getting the value ++---------------------------------------------------------------------- ++For the inode standard attributes (owner, group, timestamps, etc.), aufs ++shows the values from the topmost existing file. This behaviour is good ++for the non-dir entries since the bahaviour exactly matches the shown ++information. But for the directories, aufs considers all the same named ++entries on the lower branches. Which means, if one of the lower entry ++rejects readdir call, then aufs returns an error even if the topmost ++entry allows it. This behaviour is necessary to respect the branch fs's ++security, but can make users confused since the user-visible standard ++attributes don't match the behaviour. ++To address this issue, aufs has a mount option called dirperm1 which ++checks the permission for the topmost entry only, and ignores the lower ++entry's permission. ++ ++A similar issue can happen around XATTR. ++getxattr(2) and listxattr(2) families behave as if dirperm1 option is ++always set. Otherwise these very unpleasant situation would happen. ++- listxattr(2) may return the duplicated entries. ++- users may not be able to remove or reset the XATTR forever, ++ ++ ++XATTR/EA support in the internal (copy,move)-(up,down) ++---------------------------------------------------------------------- ++Generally the extended attributes of inode are categorized as these. ++- "security" for LSM and capability. ++- "system" for posix ACL, 'acl' mount option is required for the branch ++ fs generally. ++- "trusted" for userspace, CAP_SYS_ADMIN is required. ++- "user" for userspace, 'user_xattr' mount option is required for the ++ branch fs generally. ++ ++Moreover there are some other categories. Aufs handles these rather ++unpopular categories as the ordinary ones, ie. there is no special ++condition nor exception. ++ ++In copy-up, the support for XATTR on the dst branch may differ from the ++src branch. In this case, the copy-up operation will get an error and ++the original user operation which triggered the copy-up will fail. It ++can happen that even all copy-up will fail. ++When both of src and dst branches support XATTR and if an error occurs ++during copying XATTR, then the copy-up should fail obviously. That is a ++good reason and aufs should return an error to userspace. But when only ++the src branch support that XATTR, aufs should not return an error. ++For example, the src branch supports ACL but the dst branch doesn't ++because the dst branch may natively un-support it or temporary ++un-support it due to "noacl" mount option. Of course, the dst branch fs ++may NOT return an error even if the XATTR is not supported. It is ++totally up to the branch fs. ++ ++Anyway when the aufs internal copy-up gets an error from the dst branch ++fs, then aufs tries removing the just copied entry and returns the error ++to the userspace. The worst case of this situation will be all copy-up ++will fail. ++ ++For the copy-up operation, there two basic approaches. ++- copy the specified XATTR only (by category above), and return the ++ error unconditionally if it happens. ++- copy all XATTR, and ignore the error on the specified category only. ++ ++In order to support XATTR and to implement the correct behaviour, aufs ++chooses the latter approach and introduces some new branch attributes, ++"icexsec", "icexsys", "icextr", "icexusr", and "icexoth". ++They correspond to the XATTR namespaces (see above). Additionally, to be ++convenient, "icex" is also provided which means all "icex*" attributes ++are set (here the word "icex" stands for "ignore copy-error on XATTR"). ++ ++The meaning of these attributes is to ignore the error from setting ++XATTR on that branch. ++Note that aufs tries copying all XATTR unconditionally, and ignores the ++error from the dst branch according to the specified attributes. ++ ++Some XATTR may have its default value. The default value may come from ++the parent dir or the environment. If the default value is set at the ++file creating-time, it will be overwritten by copy-up. ++Some contradiction may happen I am afraid. ++Do we need another attribute to stop copying XATTR? I am unsure. For ++now, aufs implements the branch attributes to ignore the error. +diff -Naur null/Documentation/filesystems/aufs/design/07export.txt linux-5.15.36/Documentation/filesystems/aufs/design/07export.txt +--- /dev/null ++++ linux-5.15.36/Documentation/filesystems/aufs/design/07export.txt 2022-05-10 16:51:39.864744220 +0300 +@@ -0,0 +1,58 @@ ++ ++# Copyright (C) 2005-2021 Junjiro R. Okajima ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++Export Aufs via NFS ++---------------------------------------------------------------------- ++Here is an approach. ++- like xino/xib, add a new file 'xigen' which stores aufs inode ++ generation. ++- iget_locked(): initialize aufs inode generation for a new inode, and ++ store it in xigen file. ++- destroy_inode(): increment aufs inode generation and store it in xigen ++ file. it is necessary even if it is not unlinked, because any data of ++ inode may be changed by UDBA. ++- encode_fh(): for a root dir, simply return FILEID_ROOT. otherwise ++ build file handle by ++ + branch id (4 bytes) ++ + superblock generation (4 bytes) ++ + inode number (4 or 8 bytes) ++ + parent dir inode number (4 or 8 bytes) ++ + inode generation (4 bytes)) ++ + return value of exportfs_encode_fh() for the parent on a branch (4 ++ bytes) ++ + file handle for a branch (by exportfs_encode_fh()) ++- fh_to_dentry(): ++ + find the index of a branch from its id in handle, and check it is ++ still exist in aufs. ++ + 1st level: get the inode number from handle and search it in cache. ++ + 2nd level: if not found in cache, get the parent inode number from ++ the handle and search it in cache. and then open the found parent ++ dir, find the matching inode number by vfs_readdir() and get its ++ name, and call lookup_one_len() for the target dentry. ++ + 3rd level: if the parent dir is not cached, call ++ exportfs_decode_fh() for a branch and get the parent on a branch, ++ build a pathname of it, convert it a pathname in aufs, call ++ path_lookup(). now aufs gets a parent dir dentry, then handle it as ++ the 2nd level. ++ + to open the dir, aufs needs struct vfsmount. aufs keeps vfsmount ++ for every branch, but not itself. to get this, (currently) aufs ++ searches in current->nsproxy->mnt_ns list. it may not be a good ++ idea, but I didn't get other approach. ++ + test the generation of the gotten inode. ++- every inode operation: they may get EBUSY due to UDBA. in this case, ++ convert it into ESTALE for NFSD. ++- readdir(): call lockdep_on/off() because filldir in NFSD calls ++ lookup_one_len(), vfs_getattr(), encode_fh() and others. +diff -Naur null/Documentation/filesystems/aufs/design/08shwh.txt linux-5.15.36/Documentation/filesystems/aufs/design/08shwh.txt +--- /dev/null ++++ linux-5.15.36/Documentation/filesystems/aufs/design/08shwh.txt 2022-05-10 16:51:39.864744220 +0300 +@@ -0,0 +1,52 @@ ++ ++# Copyright (C) 2005-2021 Junjiro R. Okajima ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++Show Whiteout Mode (shwh) ++---------------------------------------------------------------------- ++Generally aufs hides the name of whiteouts. But in some cases, to show ++them is very useful for users. For instance, creating a new middle layer ++(branch) by merging existing layers. ++ ++(borrowing aufs1 HOW-TO from a user, Michael Towers) ++When you have three branches, ++- Bottom: 'system', squashfs (underlying base system), read-only ++- Middle: 'mods', squashfs, read-only ++- Top: 'overlay', ram (tmpfs), read-write ++ ++The top layer is loaded at boot time and saved at shutdown, to preserve ++the changes made to the system during the session. ++When larger changes have been made, or smaller changes have accumulated, ++the size of the saved top layer data grows. At this point, it would be ++nice to be able to merge the two overlay branches ('mods' and 'overlay') ++and rewrite the 'mods' squashfs, clearing the top layer and thus ++restoring save and load speed. ++ ++This merging is simplified by the use of another aufs mount, of just the ++two overlay branches using the 'shwh' option. ++# mount -t aufs -o ro,shwh,br:/livesys/overlay=ro+wh:/livesys/mods=rr+wh \ ++ aufs /livesys/merge_union ++ ++A merged view of these two branches is then available at ++/livesys/merge_union, and the new feature is that the whiteouts are ++visible! ++Note that in 'shwh' mode the aufs mount must be 'ro', which will disable ++writing to all branches. Also the default mode for all branches is 'ro'. ++It is now possible to save the combined contents of the two overlay ++branches to a new squashfs, e.g.: ++# mksquashfs /livesys/merge_union /path/to/newmods.squash ++ ++This new squashfs archive can be stored on the boot device and the ++initramfs will use it to replace the old one at the next boot. +diff -Naur null/Documentation/filesystems/aufs/design/10dynop.txt linux-5.15.36/Documentation/filesystems/aufs/design/10dynop.txt +--- /dev/null ++++ linux-5.15.36/Documentation/filesystems/aufs/design/10dynop.txt 2022-05-10 16:51:39.864744220 +0300 +@@ -0,0 +1,47 @@ ++ ++# Copyright (C) 2010-2021 Junjiro R. Okajima ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++Dynamically customizable FS operations ++---------------------------------------------------------------------- ++Generally FS operations (struct inode_operations, struct ++address_space_operations, struct file_operations, etc.) are defined as ++"static const", but it never means that FS have only one set of ++operation. Some FS have multiple sets of them. For instance, ext2 has ++three sets, one for XIP, for NOBH, and for normal. ++Since aufs overrides and redirects these operations, sometimes aufs has ++to change its behaviour according to the branch FS type. More importantly ++VFS acts differently if a function (member in the struct) is set or ++not. It means aufs should have several sets of operations and select one ++among them according to the branch FS definition. ++ ++In order to solve this problem and not to affect the behaviour of VFS, ++aufs defines these operations dynamically. For instance, aufs defines ++dummy direct_IO function for struct address_space_operations, but it may ++not be set to the address_space_operations actually. When the branch FS ++doesn't have it, aufs doesn't set it to its address_space_operations ++while the function definition itself is still alive. So the behaviour ++itself will not change, and it will return an error when direct_IO is ++not set. ++ ++The lifetime of these dynamically generated operation object is ++maintained by aufs branch object. When the branch is removed from aufs, ++the reference counter of the object is decremented. When it reaches ++zero, the dynamically generated operation object will be freed. ++ ++This approach is designed to support AIO (io_submit), Direct I/O and ++XIP (DAX) mainly. ++Currently this approach is applied to address_space_operations for ++regular files only. +diff -Naur null/Documentation/filesystems/aufs/README linux-5.15.36/Documentation/filesystems/aufs/README +--- /dev/null ++++ linux-5.15.36/Documentation/filesystems/aufs/README 2022-05-10 16:51:39.863744220 +0300 +@@ -0,0 +1,396 @@ ++ ++Aufs5 -- advanced multi layered unification filesystem version 5.x ++http://aufs.sf.net ++Junjiro R. Okajima ++ ++ ++0. Introduction ++---------------------------------------- ++In the early days, aufs was entirely re-designed and re-implemented ++Unionfs Version 1.x series. Adding many original ideas, approaches, ++improvements and implementations, it became totally different from ++Unionfs while keeping the basic features. ++Later, Unionfs Version 2.x series began taking some of the same ++approaches to aufs1's. ++Unionfs was being developed by Professor Erez Zadok at Stony Brook ++University and his team. ++ ++Aufs5 supports linux-v5.0 and later, If you want older kernel version ++support, ++- for linux-v4.x series, try aufs4-linux.git or aufs4-standalone.git ++- for linux-v3.x series, try aufs3-linux.git or aufs3-standalone.git ++- for linux-v2.6.16 and later, try aufs2-2.6.git, aufs2-standalone.git ++ or aufs1 from CVS on SourceForge. ++ ++Note: it becomes clear that "Aufs was rejected. Let's give it up." ++ According to Christoph Hellwig, linux rejects all union-type ++ filesystems but UnionMount. ++ ++ ++PS. Al Viro seems have a plan to merge aufs as well as overlayfs and ++ UnionMount, and he pointed out an issue around a directory mutex ++ lock and aufs addressed it. But it is still unsure whether aufs will ++ be merged (or any other union solution). ++ ++ ++ ++1. Features ++---------------------------------------- ++- unite several directories into a single virtual filesystem. The member ++ directory is called as a branch. ++- you can specify the permission flags to the branch, which are 'readonly', ++ 'readwrite' and 'whiteout-able.' ++- by upper writable branch, internal copyup and whiteout, files/dirs on ++ readonly branch are modifiable logically. ++- dynamic branch manipulation, add, del. ++- etc... ++ ++Also there are many enhancements in aufs, such as: ++- test only the highest one for the directory permission (dirperm1) ++- copyup on open (coo=) ++- 'move' policy for copy-up between two writable branches, after ++ checking free space. ++- xattr, acl ++- readdir(3) in userspace. ++- keep inode number by external inode number table ++- keep the timestamps of file/dir in internal copyup operation ++- seekable directory, supporting NFS readdir. ++- whiteout is hardlinked in order to reduce the consumption of inodes ++ on branch ++- do not copyup, nor create a whiteout when it is unnecessary ++- revert a single systemcall when an error occurs in aufs ++- remount interface instead of ioctl ++- maintain /etc/mtab by an external command, /sbin/mount.aufs. ++- loopback mounted filesystem as a branch ++- kernel thread for removing the dir who has a plenty of whiteouts ++- support copyup sparse file (a file which has a 'hole' in it) ++- default permission flags for branches ++- selectable permission flags for ro branch, whether whiteout can ++ exist or not ++- export via NFS. ++- support /fs/aufs and /aufs. ++- support multiple writable branches, some policies to select one ++ among multiple writable branches. ++- a new semantics for link(2) and rename(2) to support multiple ++ writable branches. ++- no glibc changes are required. ++- pseudo hardlink (hardlink over branches) ++- allow a direct access manually to a file on branch, e.g. bypassing aufs. ++ including NFS or remote filesystem branch. ++- userspace wrapper for pathconf(3)/fpathconf(3) with _PC_LINK_MAX. ++- and more... ++ ++Currently these features are dropped temporary from aufs5. ++See design/08plan.txt in detail. ++- nested mount, i.e. aufs as readonly no-whiteout branch of another aufs ++ (robr) ++- statistics of aufs thread (/sys/fs/aufs/stat) ++ ++Features or just an idea in the future (see also design/*.txt), ++- reorder the branch index without del/re-add. ++- permanent xino files for NFSD ++- an option for refreshing the opened files after add/del branches ++- light version, without branch manipulation. (unnecessary?) ++- copyup in userspace ++- inotify in userspace ++- readv/writev ++ ++ ++2. Download ++---------------------------------------- ++There are three GIT trees for aufs5, aufs5-linux.git, ++aufs5-standalone.git, and aufs-util.git. Note that there is no "5" in ++"aufs-util.git." ++While the aufs-util is always necessary, you need either of aufs5-linux ++or aufs5-standalone. ++ ++The aufs5-linux tree includes the whole linux mainline GIT tree, ++git://git.kernel.org/.../torvalds/linux.git. ++And you cannot select CONFIG_AUFS_FS=m for this version, eg. you cannot ++build aufs5 as an external kernel module. ++Several extra patches are not included in this tree. Only ++aufs5-standalone tree contains them. They are described in the later ++section "Configuration and Compilation." ++ ++On the other hand, the aufs5-standalone tree has only aufs source files ++and necessary patches, and you can select CONFIG_AUFS_FS=m. ++But you need to apply all aufs patches manually. ++ ++You will find GIT branches whose name is in form of "aufs5.x" where "x" ++represents the linux kernel version, "linux-5.x". For instance, ++"aufs5.0" is for linux-5.0. For latest "linux-5.x-rcN", use ++"aufs5.x-rcN" branch. ++ ++o aufs5-linux tree ++$ git clone --reference /your/linux/git/tree \ ++ git://github.com/sfjro/aufs5-linux.git aufs5-linux.git ++- if you don't have linux GIT tree, then remove "--reference ..." ++$ cd aufs5-linux.git ++$ git checkout origin/aufs5.0 ++ ++Or You may want to directly git-pull aufs into your linux GIT tree, and ++leave the patch-work to GIT. ++$ cd /your/linux/git/tree ++$ git remote add aufs5 git://github.com/sfjro/aufs5-linux.git ++$ git fetch aufs5 ++$ git checkout -b my5.0 v5.0 ++$ (add your local change...) ++$ git pull aufs5 aufs5.0 ++- now you have v5.0 + your_changes + aufs5.0 in you my5.0 branch. ++- you may need to solve some conflicts between your_changes and ++ aufs5.0. in this case, git-rerere is recommended so that you can ++ solve the similar conflicts automatically when you upgrade to 5.1 or ++ later in the future. ++ ++o aufs5-standalone tree ++$ git clone git://github.com/sfjro/aufs5-standalone.git aufs5-standalone.git ++$ cd aufs5-standalone.git ++$ git checkout origin/aufs5.0 ++ ++o aufs-util tree ++$ git clone git://git.code.sf.net/p/aufs/aufs-util aufs-util.git ++- note that the public aufs-util.git is on SourceForge instead of ++ GitHUB. ++$ cd aufs-util.git ++$ git checkout origin/aufs5.0 ++ ++Note: The 5.x-rcN branch is to be used with `rc' kernel versions ONLY. ++The minor version number, 'x' in '5.x', of aufs may not always ++follow the minor version number of the kernel. ++Because changes in the kernel that cause the use of a new ++minor version number do not always require changes to aufs-util. ++ ++Since aufs-util has its own minor version number, you may not be ++able to find a GIT branch in aufs-util for your kernel's ++exact minor version number. ++In this case, you should git-checkout the branch for the ++nearest lower number. ++ ++For (an unreleased) example: ++If you are using "linux-5.10" and the "aufs5.10" branch ++does not exist in aufs-util repository, then "aufs5.9", "aufs5.8" ++or something numerically smaller is the branch for your kernel. ++ ++Also you can view all branches by ++ $ git branch -a ++ ++ ++3. Configuration and Compilation ++---------------------------------------- ++Make sure you have git-checkout'ed the correct branch. ++ ++For aufs5-linux tree, ++- enable CONFIG_AUFS_FS. ++- set other aufs configurations if necessary. ++- for aufs5.13 and later ++ Because aufs is not only an ordinary filesystem (callee of VFS), but ++ also a caller of VFS functions for branch filesystems, subclassing of ++ the internal locks for LOCKDEP is necessary. LOCKDEP is a debugging ++ feature of linux kernel. If you enable CONFIG_LOCKDEP, then you will ++ need to customize some LOCKDEP numbers. Here are what I use on my ++ test environment. ++ CONFIG_LOCKDEP_BITS=21 ++ CONFIG_LOCKDEP_CHAINS_BITS=21 ++ CONFIG_LOCKDEP_STACK_TRACE_BITS=24 ++ ++For aufs5-standalone tree, ++There are several ways to build. ++ ++1. ++- apply ./aufs5-kbuild.patch to your kernel source files. ++- apply ./aufs5-base.patch too. ++- apply ./aufs5-mmap.patch too. ++- apply ./aufs5-standalone.patch too, if you have a plan to set ++ CONFIG_AUFS_FS=m. otherwise you don't need ./aufs5-standalone.patch. ++- copy ./{Documentation,fs,include/uapi/linux/aufs_type.h} files to your ++ kernel source tree. Never copy $PWD/include/uapi/linux/Kbuild. ++- enable CONFIG_AUFS_FS, you can select either ++ =m or =y. ++- and build your kernel as usual. ++- install the built kernel. ++- install the header files too by "make headers_install" to the ++ directory where you specify. By default, it is $PWD/usr. ++ "make help" shows a brief note for headers_install. ++- and reboot your system. ++ ++2. ++- module only (CONFIG_AUFS_FS=m). ++- apply ./aufs5-base.patch to your kernel source files. ++- apply ./aufs5-mmap.patch too. ++- apply ./aufs5-standalone.patch too. ++- build your kernel, don't forget "make headers_install", and reboot. ++- edit ./config.mk and set other aufs configurations if necessary. ++ Note: You should read $PWD/fs/aufs/Kconfig carefully which describes ++ every aufs configurations. ++- build the module by simple "make". ++- you can specify ${KDIR} make variable which points to your kernel ++ source tree. ++- install the files ++ + run "make install" to install the aufs module, or copy the built ++ $PWD/aufs.ko to /lib/modules/... and run depmod -a (or reboot simply). ++ + run "make install_headers" (instead of headers_install) to install ++ the modified aufs header file (you can specify DESTDIR which is ++ available in aufs standalone version's Makefile only), or copy ++ $PWD/usr/include/linux/aufs_type.h to /usr/include/linux or wherever ++ you like manually. By default, the target directory is $PWD/usr. ++- no need to apply aufs5-kbuild.patch, nor copying source files to your ++ kernel source tree. ++ ++Note: The header file aufs_type.h is necessary to build aufs-util ++ as well as "make headers_install" in the kernel source tree. ++ headers_install is subject to be forgotten, but it is essentially ++ necessary, not only for building aufs-util. ++ You may not meet problems without headers_install in some older ++ version though. ++ ++And then, ++- read README in aufs-util, build and install it ++- note that your distribution may contain an obsoleted version of ++ aufs_type.h in /usr/include/linux or something. When you build aufs ++ utilities, make sure that your compiler refers the correct aufs header ++ file which is built by "make headers_install." ++- if you want to use readdir(3) in userspace or pathconf(3) wrapper, ++ then run "make install_ulib" too. And refer to the aufs manual in ++ detail. ++ ++There several other patches in aufs5-standalone.git. They are all ++optional. When you meet some problems, they will help you. ++- aufs5-loopback.patch ++ Supports a nested loopback mount in a branch-fs. This patch is ++ unnecessary until aufs produces a message like "you may want to try ++ another patch for loopback file". ++- vfs-ino.patch ++ Modifies a system global kernel internal function get_next_ino() in ++ order to stop assigning 0 for an inode-number. Not directly related to ++ aufs, but recommended generally. ++- tmpfs-idr.patch ++ Keeps the tmpfs inode number as the lowest value. Effective to reduce ++ the size of aufs XINO files for tmpfs branch. Also it prevents the ++ duplication of inode number, which is important for backup tools and ++ other utilities. When you find aufs XINO files for tmpfs branch ++ growing too much, try this patch. ++ ++ ++4. Usage ++---------------------------------------- ++At first, make sure aufs-util are installed, and please read the aufs ++manual, aufs.5 in aufs-util.git tree. ++$ man -l aufs.5 ++ ++And then, ++$ mkdir /tmp/rw /tmp/aufs ++# mount -t aufs -o br=/tmp/rw:${HOME} none /tmp/aufs ++ ++Here is another example. The result is equivalent. ++# mount -t aufs -o br=/tmp/rw=rw:${HOME}=ro none /tmp/aufs ++ Or ++# mount -t aufs -o br:/tmp/rw none /tmp/aufs ++# mount -o remount,append:${HOME} /tmp/aufs ++ ++Then, you can see whole tree of your home dir through /tmp/aufs. If ++you modify a file under /tmp/aufs, the one on your home directory is ++not affected, instead the same named file will be newly created under ++/tmp/rw. And all of your modification to a file will be applied to ++the one under /tmp/rw. This is called the file based Copy on Write ++(COW) method. ++Aufs mount options are described in aufs.5. ++If you run chroot or something and make your aufs as a root directory, ++then you need to customize the shutdown script. See the aufs manual in ++detail. ++ ++Additionally, there are some sample usages of aufs which are a ++diskless system with network booting, and LiveCD over NFS. ++See sample dir in CVS tree on SourceForge. ++ ++ ++5. Contact ++---------------------------------------- ++When you have any problems or strange behaviour in aufs, please let me ++know with: ++- /proc/mounts (instead of the output of mount(8)) ++- /sys/module/aufs/* ++- /sys/fs/aufs/* (if you have them) ++- /debug/aufs/* (if you have them) ++- linux kernel version ++ if your kernel is not plain, for example modified by distributor, ++ the url where i can download its source is necessary too. ++- aufs version which was printed at loading the module or booting the ++ system, instead of the date you downloaded. ++- configuration (define/undefine CONFIG_AUFS_xxx) ++- kernel configuration or /proc/config.gz (if you have it) ++- LSM (linux security module, if you are using) ++- behaviour which you think to be incorrect ++- actual operation, reproducible one is better ++- mailto: aufs-users at lists.sourceforge.net ++ ++Usually, I don't watch the Public Areas(Bugs, Support Requests, Patches, ++and Feature Requests) on SourceForge. Please join and write to ++aufs-users ML. ++ ++ ++6. Acknowledgements ++---------------------------------------- ++Thanks to everyone who have tried and are using aufs, whoever ++have reported a bug or any feedback. ++ ++Especially donators: ++Tomas Matejicek(slax.org) made a donation (much more than once). ++ Since Apr 2010, Tomas M (the author of Slax and Linux Live ++ scripts) is making "doubling" donations. ++ Unfortunately I cannot list all of the donators, but I really ++ appreciate. ++ It ends Aug 2010, but the ordinary donation URL is still available. ++ ++Dai Itasaka made a donation (2007/8). ++Chuck Smith made a donation (2008/4, 10 and 12). ++Henk Schoneveld made a donation (2008/9). ++Chih-Wei Huang, ASUS, CTC donated Eee PC 4G (2008/10). ++Francois Dupoux made a donation (2008/11). ++Bruno Cesar Ribas and Luis Carlos Erpen de Bona, C3SL serves public ++ aufs2 GIT tree (2009/2). ++William Grant made a donation (2009/3). ++Patrick Lane made a donation (2009/4). ++The Mail Archive (mail-archive.com) made donations (2009/5). ++Nippy Networks (Ed Wildgoose) made a donation (2009/7). ++New Dream Network, LLC (www.dreamhost.com) made a donation (2009/11). ++Pavel Pronskiy made a donation (2011/2). ++Iridium and Inmarsat satellite phone retailer (www.mailasail.com), Nippy ++ Networks (Ed Wildgoose) made a donation for hardware (2011/3). ++Max Lekomcev (DOM-TV project) made a donation (2011/7, 12, 2012/3, 6 and ++11). ++Sam Liddicott made a donation (2011/9). ++Era Scarecrow made a donation (2013/4). ++Bor Ratajc made a donation (2013/4). ++Alessandro Gorreta made a donation (2013/4). ++POIRETTE Marc made a donation (2013/4). ++Alessandro Gorreta made a donation (2013/4). ++lauri kasvandik made a donation (2013/5). ++"pemasu from Finland" made a donation (2013/7). ++The Parted Magic Project made a donation (2013/9 and 11). ++Pavel Barta made a donation (2013/10). ++Nikolay Pertsev made a donation (2014/5). ++James B made a donation (2014/7, 2015/7, and 2021/12). ++Stefano Di Biase made a donation (2014/8). ++Daniel Epellei made a donation (2015/1). ++OmegaPhil made a donation (2016/1, 2018/4). ++Tomasz Szewczyk made a donation (2016/4). ++James Burry made a donation (2016/12). ++Carsten Rose made a donation (2018/9). ++Porteus Kiosk made a donation (2018/10). ++ ++Thank you very much. ++Donations are always, including future donations, very important and ++helpful for me to keep on developing aufs. ++ ++ ++7. ++---------------------------------------- ++If you are an experienced user, no explanation is needed. Aufs is ++just a linux filesystem. ++ ++ ++Enjoy! ++ ++# Local variables: ; ++# mode: text; ++# End: ; +diff -Naur null/fs/aufs/aufs.h linux-5.15.36/fs/aufs/aufs.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/aufs.h 2022-05-10 16:51:39.866744220 +0300 +@@ -0,0 +1,62 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * all header files ++ */ ++ ++#ifndef __AUFS_H__ ++#define __AUFS_H__ ++ ++#ifdef __KERNEL__ ++ ++#define AuStub(type, name, body, ...) \ ++ static inline type name(__VA_ARGS__) { body; } ++ ++#define AuStubVoid(name, ...) \ ++ AuStub(void, name, , __VA_ARGS__) ++#define AuStubInt0(name, ...) \ ++ AuStub(int, name, return 0, __VA_ARGS__) ++ ++#include "debug.h" ++ ++#include "branch.h" ++#include "cpup.h" ++#include "dcsub.h" ++#include "dbgaufs.h" ++#include "dentry.h" ++#include "dir.h" ++#include "dirren.h" ++#include "dynop.h" ++#include "file.h" ++#include "fstype.h" ++#include "hbl.h" ++#include "inode.h" ++#include "lcnt.h" ++#include "loop.h" ++#include "module.h" ++#include "opts.h" ++#include "rwsem.h" ++#include "super.h" ++#include "sysaufs.h" ++#include "vfsub.h" ++#include "whout.h" ++#include "wkq.h" ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_H__ */ +diff -Naur null/fs/aufs/branch.c linux-5.15.36/fs/aufs/branch.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/branch.c 2022-05-10 16:51:39.866744220 +0300 +@@ -0,0 +1,1427 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * branch management ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++/* ++ * free a single branch ++ */ ++static void au_br_do_free(struct au_branch *br) ++{ ++ int i; ++ struct au_wbr *wbr; ++ struct au_dykey **key; ++ ++ au_hnotify_fin_br(br); ++ /* always, regardless the mount option */ ++ au_dr_hino_free(&br->br_dirren); ++ au_xino_put(br); ++ ++ AuLCntZero(au_lcnt_read(&br->br_nfiles, /*do_rev*/0)); ++ au_lcnt_fin(&br->br_nfiles, /*do_sync*/0); ++ AuLCntZero(au_lcnt_read(&br->br_count, /*do_rev*/0)); ++ au_lcnt_fin(&br->br_count, /*do_sync*/0); ++ ++ wbr = br->br_wbr; ++ if (wbr) { ++ for (i = 0; i < AuBrWh_Last; i++) ++ dput(wbr->wbr_wh[i]); ++ AuDebugOn(atomic_read(&wbr->wbr_wh_running)); ++ AuRwDestroy(&wbr->wbr_wh_rwsem); ++ } ++ ++ if (br->br_fhsm) { ++ au_br_fhsm_fin(br->br_fhsm); ++ au_kfree_try_rcu(br->br_fhsm); ++ } ++ ++ key = br->br_dykey; ++ for (i = 0; i < AuBrDynOp; i++, key++) ++ if (*key) ++ au_dy_put(*key); ++ else ++ break; ++ ++ /* recursive lock, s_umount of branch's */ ++ /* synchronize_rcu(); */ /* why? */ ++ lockdep_off(); ++ path_put(&br->br_path); ++ lockdep_on(); ++ au_kfree_rcu(wbr); ++ au_lcnt_wait_for_fin(&br->br_nfiles); ++ au_lcnt_wait_for_fin(&br->br_count); ++ /* I don't know why, but percpu_refcount requires this */ ++ /* synchronize_rcu(); */ ++ au_kfree_rcu(br); ++} ++ ++/* ++ * frees all branches ++ */ ++void au_br_free(struct au_sbinfo *sbinfo) ++{ ++ aufs_bindex_t bmax; ++ struct au_branch **br; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ bmax = sbinfo->si_bbot + 1; ++ br = sbinfo->si_branch; ++ while (bmax--) ++ au_br_do_free(*br++); ++} ++ ++/* ++ * find the index of a branch which is specified by @br_id. ++ */ ++int au_br_index(struct super_block *sb, aufs_bindex_t br_id) ++{ ++ aufs_bindex_t bindex, bbot; ++ ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) ++ if (au_sbr_id(sb, bindex) == br_id) ++ return bindex; ++ return -1; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * add a branch ++ */ ++ ++static int test_overlap(struct super_block *sb, struct dentry *h_adding, ++ struct dentry *h_root) ++{ ++ if (unlikely(h_adding == h_root ++ || au_test_loopback_overlap(sb, h_adding))) ++ return 1; ++ if (h_adding->d_sb != h_root->d_sb) ++ return 0; ++ return au_test_subdir(h_adding, h_root) ++ || au_test_subdir(h_root, h_adding); ++} ++ ++/* ++ * returns a newly allocated branch. @new_nbranch is a number of branches ++ * after adding a branch. ++ */ ++static struct au_branch *au_br_alloc(struct super_block *sb, int new_nbranch, ++ int perm) ++{ ++ struct au_branch *add_branch; ++ struct dentry *root; ++ struct inode *inode; ++ int err; ++ ++ err = -ENOMEM; ++ add_branch = kzalloc(sizeof(*add_branch), GFP_NOFS); ++ if (unlikely(!add_branch)) ++ goto out; ++ add_branch->br_xino = au_xino_alloc(/*nfile*/1); ++ if (unlikely(!add_branch->br_xino)) ++ goto out_br; ++ err = au_hnotify_init_br(add_branch, perm); ++ if (unlikely(err)) ++ goto out_xino; ++ ++ if (au_br_writable(perm)) { ++ /* may be freed separately at changing the branch permission */ ++ add_branch->br_wbr = kzalloc(sizeof(*add_branch->br_wbr), ++ GFP_NOFS); ++ if (unlikely(!add_branch->br_wbr)) ++ goto out_hnotify; ++ } ++ ++ if (au_br_fhsm(perm)) { ++ err = au_fhsm_br_alloc(add_branch); ++ if (unlikely(err)) ++ goto out_wbr; ++ } ++ ++ root = sb->s_root; ++ err = au_sbr_realloc(au_sbi(sb), new_nbranch, /*may_shrink*/0); ++ if (!err) ++ err = au_di_realloc(au_di(root), new_nbranch, /*may_shrink*/0); ++ if (!err) { ++ inode = d_inode(root); ++ err = au_hinode_realloc(au_ii(inode), new_nbranch, ++ /*may_shrink*/0); ++ } ++ if (!err) ++ return add_branch; /* success */ ++ ++out_wbr: ++ au_kfree_rcu(add_branch->br_wbr); ++out_hnotify: ++ au_hnotify_fin_br(add_branch); ++out_xino: ++ au_xino_put(add_branch); ++out_br: ++ au_kfree_rcu(add_branch); ++out: ++ return ERR_PTR(err); ++} ++ ++/* ++ * test if the branch permission is legal or not. ++ */ ++static int test_br(struct inode *inode, int brperm, char *path) ++{ ++ int err; ++ ++ err = (au_br_writable(brperm) && IS_RDONLY(inode)); ++ if (!err) ++ goto out; ++ ++ err = -EINVAL; ++ pr_err("write permission for readonly mount or inode, %s\n", path); ++ ++out: ++ return err; ++} ++ ++/* ++ * returns: ++ * 0: success, the caller will add it ++ * plus: success, it is already unified, the caller should ignore it ++ * minus: error ++ */ ++static int test_add(struct super_block *sb, struct au_opt_add *add, int remount) ++{ ++ int err; ++ aufs_bindex_t bbot, bindex; ++ struct dentry *root, *h_dentry; ++ struct inode *inode, *h_inode; ++ ++ root = sb->s_root; ++ bbot = au_sbbot(sb); ++ if (unlikely(bbot >= 0 ++ && au_find_dbindex(root, add->path.dentry) >= 0)) { ++ err = 1; ++ if (!remount) { ++ err = -EINVAL; ++ pr_err("%s duplicated\n", add->pathname); ++ } ++ goto out; ++ } ++ ++ err = -ENOSPC; /* -E2BIG; */ ++ if (unlikely(AUFS_BRANCH_MAX <= add->bindex ++ || AUFS_BRANCH_MAX - 1 <= bbot)) { ++ pr_err("number of branches exceeded %s\n", add->pathname); ++ goto out; ++ } ++ ++ err = -EDOM; ++ if (unlikely(add->bindex < 0 || bbot + 1 < add->bindex)) { ++ pr_err("bad index %d\n", add->bindex); ++ goto out; ++ } ++ ++ inode = d_inode(add->path.dentry); ++ err = -ENOENT; ++ if (unlikely(!inode->i_nlink)) { ++ pr_err("no existence %s\n", add->pathname); ++ goto out; ++ } ++ ++ err = -EINVAL; ++ if (unlikely(inode->i_sb == sb)) { ++ pr_err("%s must be outside\n", add->pathname); ++ goto out; ++ } ++ ++ if (unlikely(au_test_fs_unsuppoted(inode->i_sb))) { ++ pr_err("unsupported filesystem, %s (%s)\n", ++ add->pathname, au_sbtype(inode->i_sb)); ++ goto out; ++ } ++ ++ if (unlikely(inode->i_sb->s_stack_depth)) { ++ pr_err("already stacked, %s (%s)\n", ++ add->pathname, au_sbtype(inode->i_sb)); ++ goto out; ++ } ++ ++ err = test_br(d_inode(add->path.dentry), add->perm, add->pathname); ++ if (unlikely(err)) ++ goto out; ++ ++ if (bbot < 0) ++ return 0; /* success */ ++ ++ err = -EINVAL; ++ for (bindex = 0; bindex <= bbot; bindex++) ++ if (unlikely(test_overlap(sb, add->path.dentry, ++ au_h_dptr(root, bindex)))) { ++ pr_err("%s is overlapped\n", add->pathname); ++ goto out; ++ } ++ ++ err = 0; ++ if (au_opt_test(au_mntflags(sb), WARN_PERM)) { ++ h_dentry = au_h_dptr(root, 0); ++ h_inode = d_inode(h_dentry); ++ if ((h_inode->i_mode & S_IALLUGO) != (inode->i_mode & S_IALLUGO) ++ || !uid_eq(h_inode->i_uid, inode->i_uid) ++ || !gid_eq(h_inode->i_gid, inode->i_gid)) ++ pr_warn("uid/gid/perm %s %u/%u/0%o, %u/%u/0%o\n", ++ add->pathname, ++ i_uid_read(inode), i_gid_read(inode), ++ (inode->i_mode & S_IALLUGO), ++ i_uid_read(h_inode), i_gid_read(h_inode), ++ (h_inode->i_mode & S_IALLUGO)); ++ } ++ ++out: ++ return err; ++} ++ ++/* ++ * initialize or clean the whiteouts for an adding branch ++ */ ++static int au_br_init_wh(struct super_block *sb, struct au_branch *br, ++ int new_perm) ++{ ++ int err, old_perm; ++ aufs_bindex_t bindex; ++ struct inode *h_inode; ++ struct au_wbr *wbr; ++ struct au_hinode *hdir; ++ struct dentry *h_dentry; ++ ++ err = vfsub_mnt_want_write(au_br_mnt(br)); ++ if (unlikely(err)) ++ goto out; ++ ++ wbr = br->br_wbr; ++ old_perm = br->br_perm; ++ br->br_perm = new_perm; ++ hdir = NULL; ++ h_inode = NULL; ++ bindex = au_br_index(sb, br->br_id); ++ if (0 <= bindex) { ++ hdir = au_hi(d_inode(sb->s_root), bindex); ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ } else { ++ h_dentry = au_br_dentry(br); ++ h_inode = d_inode(h_dentry); ++ inode_lock_nested(h_inode, AuLsc_I_PARENT); ++ } ++ if (!wbr) ++ err = au_wh_init(br, sb); ++ else { ++ wbr_wh_write_lock(wbr); ++ err = au_wh_init(br, sb); ++ wbr_wh_write_unlock(wbr); ++ } ++ if (hdir) ++ au_hn_inode_unlock(hdir); ++ else ++ inode_unlock(h_inode); ++ vfsub_mnt_drop_write(au_br_mnt(br)); ++ br->br_perm = old_perm; ++ ++ if (!err && wbr && !au_br_writable(new_perm)) { ++ au_kfree_rcu(wbr); ++ br->br_wbr = NULL; ++ } ++ ++out: ++ return err; ++} ++ ++static int au_wbr_init(struct au_branch *br, struct super_block *sb, ++ int perm) ++{ ++ int err; ++ struct kstatfs kst; ++ struct au_wbr *wbr; ++ ++ wbr = br->br_wbr; ++ au_rw_init(&wbr->wbr_wh_rwsem); ++ atomic_set(&wbr->wbr_wh_running, 0); ++ ++ /* ++ * a limit for rmdir/rename a dir ++ * cf. AUFS_MAX_NAMELEN in include/uapi/linux/aufs_type.h ++ */ ++ err = vfs_statfs(&br->br_path, &kst); ++ if (unlikely(err)) ++ goto out; ++ err = -EINVAL; ++ if (kst.f_namelen >= NAME_MAX) ++ err = au_br_init_wh(sb, br, perm); ++ else ++ pr_err("%pd(%s), unsupported namelen %ld\n", ++ au_br_dentry(br), ++ au_sbtype(au_br_dentry(br)->d_sb), kst.f_namelen); ++ ++out: ++ return err; ++} ++ ++/* initialize a new branch */ ++static int au_br_init(struct au_branch *br, struct super_block *sb, ++ struct au_opt_add *add) ++{ ++ int err; ++ struct au_branch *brbase; ++ struct file *xf; ++ struct inode *h_inode; ++ ++ err = 0; ++ br->br_perm = add->perm; ++ br->br_path = add->path; /* set first, path_get() later */ ++ spin_lock_init(&br->br_dykey_lock); ++ au_lcnt_init(&br->br_nfiles, /*release*/NULL); ++ au_lcnt_init(&br->br_count, /*release*/NULL); ++ br->br_id = au_new_br_id(sb); ++ AuDebugOn(br->br_id < 0); ++ ++ /* always, regardless the given option */ ++ err = au_dr_br_init(sb, br, &add->path); ++ if (unlikely(err)) ++ goto out_err; ++ ++ if (au_br_writable(add->perm)) { ++ err = au_wbr_init(br, sb, add->perm); ++ if (unlikely(err)) ++ goto out_err; ++ } ++ ++ if (au_opt_test(au_mntflags(sb), XINO)) { ++ brbase = au_sbr(sb, 0); ++ xf = au_xino_file(brbase->br_xino, /*idx*/-1); ++ AuDebugOn(!xf); ++ h_inode = d_inode(add->path.dentry); ++ err = au_xino_init_br(sb, br, h_inode->i_ino, &xf->f_path); ++ if (unlikely(err)) { ++ AuDebugOn(au_xino_file(br->br_xino, /*idx*/-1)); ++ goto out_err; ++ } ++ } ++ ++ sysaufs_br_init(br); ++ path_get(&br->br_path); ++ goto out; /* success */ ++ ++out_err: ++ memset(&br->br_path, 0, sizeof(br->br_path)); ++out: ++ return err; ++} ++ ++static void au_br_do_add_brp(struct au_sbinfo *sbinfo, aufs_bindex_t bindex, ++ struct au_branch *br, aufs_bindex_t bbot, ++ aufs_bindex_t amount) ++{ ++ struct au_branch **brp; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ brp = sbinfo->si_branch + bindex; ++ memmove(brp + 1, brp, sizeof(*brp) * amount); ++ *brp = br; ++ sbinfo->si_bbot++; ++ if (unlikely(bbot < 0)) ++ sbinfo->si_bbot = 0; ++} ++ ++static void au_br_do_add_hdp(struct au_dinfo *dinfo, aufs_bindex_t bindex, ++ aufs_bindex_t bbot, aufs_bindex_t amount) ++{ ++ struct au_hdentry *hdp; ++ ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ hdp = au_hdentry(dinfo, bindex); ++ memmove(hdp + 1, hdp, sizeof(*hdp) * amount); ++ au_h_dentry_init(hdp); ++ dinfo->di_bbot++; ++ if (unlikely(bbot < 0)) ++ dinfo->di_btop = 0; ++} ++ ++static void au_br_do_add_hip(struct au_iinfo *iinfo, aufs_bindex_t bindex, ++ aufs_bindex_t bbot, aufs_bindex_t amount) ++{ ++ struct au_hinode *hip; ++ ++ AuRwMustWriteLock(&iinfo->ii_rwsem); ++ ++ hip = au_hinode(iinfo, bindex); ++ memmove(hip + 1, hip, sizeof(*hip) * amount); ++ au_hinode_init(hip); ++ iinfo->ii_bbot++; ++ if (unlikely(bbot < 0)) ++ iinfo->ii_btop = 0; ++} ++ ++static void au_br_do_add(struct super_block *sb, struct au_branch *br, ++ aufs_bindex_t bindex) ++{ ++ struct dentry *root, *h_dentry; ++ struct inode *root_inode, *h_inode; ++ aufs_bindex_t bbot, amount; ++ ++ root = sb->s_root; ++ root_inode = d_inode(root); ++ bbot = au_sbbot(sb); ++ amount = bbot + 1 - bindex; ++ h_dentry = au_br_dentry(br); ++ au_sbilist_lock(); ++ au_br_do_add_brp(au_sbi(sb), bindex, br, bbot, amount); ++ au_br_do_add_hdp(au_di(root), bindex, bbot, amount); ++ au_br_do_add_hip(au_ii(root_inode), bindex, bbot, amount); ++ au_set_h_dptr(root, bindex, dget(h_dentry)); ++ h_inode = d_inode(h_dentry); ++ au_set_h_iptr(root_inode, bindex, au_igrab(h_inode), /*flags*/0); ++ au_sbilist_unlock(); ++} ++ ++int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount) ++{ ++ int err; ++ aufs_bindex_t bbot, add_bindex; ++ struct dentry *root, *h_dentry; ++ struct inode *root_inode; ++ struct au_branch *add_branch; ++ ++ root = sb->s_root; ++ root_inode = d_inode(root); ++ IMustLock(root_inode); ++ IiMustWriteLock(root_inode); ++ err = test_add(sb, add, remount); ++ if (unlikely(err < 0)) ++ goto out; ++ if (err) { ++ err = 0; ++ goto out; /* success */ ++ } ++ ++ bbot = au_sbbot(sb); ++ add_branch = au_br_alloc(sb, bbot + 2, add->perm); ++ err = PTR_ERR(add_branch); ++ if (IS_ERR(add_branch)) ++ goto out; ++ ++ err = au_br_init(add_branch, sb, add); ++ if (unlikely(err)) { ++ au_br_do_free(add_branch); ++ goto out; ++ } ++ ++ add_bindex = add->bindex; ++ sysaufs_brs_del(sb, add_bindex); /* remove successors */ ++ au_br_do_add(sb, add_branch, add_bindex); ++ sysaufs_brs_add(sb, add_bindex); /* append successors */ ++ dbgaufs_brs_add(sb, add_bindex, /*topdown*/0); /* rename successors */ ++ ++ h_dentry = add->path.dentry; ++ if (!add_bindex) { ++ au_cpup_attr_all(root_inode, /*force*/1); ++ sb->s_maxbytes = h_dentry->d_sb->s_maxbytes; ++ } else ++ au_add_nlink(root_inode, d_inode(h_dentry)); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static unsigned long long au_farray_cb(struct super_block *sb, void *a, ++ unsigned long long max __maybe_unused, ++ void *arg) ++{ ++ unsigned long long n; ++ struct file **p, *f; ++ struct hlist_bl_head *files; ++ struct hlist_bl_node *pos; ++ struct au_finfo *finfo; ++ ++ n = 0; ++ p = a; ++ files = &au_sbi(sb)->si_files; ++ hlist_bl_lock(files); ++ hlist_bl_for_each_entry(finfo, pos, files, fi_hlist) { ++ f = finfo->fi_file; ++ if (file_count(f) ++ && !special_file(file_inode(f)->i_mode)) { ++ get_file(f); ++ *p++ = f; ++ n++; ++ AuDebugOn(n > max); ++ } ++ } ++ hlist_bl_unlock(files); ++ ++ return n; ++} ++ ++static struct file **au_farray_alloc(struct super_block *sb, ++ unsigned long long *max) ++{ ++ struct au_sbinfo *sbi; ++ ++ sbi = au_sbi(sb); ++ *max = au_lcnt_read(&sbi->si_nfiles, /*do_rev*/1); ++ return au_array_alloc(max, au_farray_cb, sb, /*arg*/NULL); ++} ++ ++static void au_farray_free(struct file **a, unsigned long long max) ++{ ++ unsigned long long ull; ++ ++ for (ull = 0; ull < max; ull++) ++ if (a[ull]) ++ fput(a[ull]); ++ kvfree(a); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * delete a branch ++ */ ++ ++/* to show the line number, do not make it inlined function */ ++#define AuVerbose(do_info, fmt, ...) do { \ ++ if (do_info) \ ++ pr_info(fmt, ##__VA_ARGS__); \ ++} while (0) ++ ++static int au_test_ibusy(struct inode *inode, aufs_bindex_t btop, ++ aufs_bindex_t bbot) ++{ ++ return (inode && !S_ISDIR(inode->i_mode)) || btop == bbot; ++} ++ ++static int au_test_dbusy(struct dentry *dentry, aufs_bindex_t btop, ++ aufs_bindex_t bbot) ++{ ++ return au_test_ibusy(d_inode(dentry), btop, bbot); ++} ++ ++/* ++ * test if the branch is deletable or not. ++ */ ++static int test_dentry_busy(struct dentry *root, aufs_bindex_t bindex, ++ unsigned int sigen, const unsigned int verbose) ++{ ++ int err, i, j, ndentry; ++ aufs_bindex_t btop, bbot; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry *d; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, root, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ for (i = 0; !err && i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ ndentry = dpage->ndentry; ++ for (j = 0; !err && j < ndentry; j++) { ++ d = dpage->dentries[j]; ++ AuDebugOn(au_dcount(d) <= 0); ++ if (!au_digen_test(d, sigen)) { ++ di_read_lock_child(d, AuLock_IR); ++ if (unlikely(au_dbrange_test(d))) { ++ di_read_unlock(d, AuLock_IR); ++ continue; ++ } ++ } else { ++ di_write_lock_child(d); ++ if (unlikely(au_dbrange_test(d))) { ++ di_write_unlock(d); ++ continue; ++ } ++ err = au_reval_dpath(d, sigen); ++ if (!err) ++ di_downgrade_lock(d, AuLock_IR); ++ else { ++ di_write_unlock(d); ++ break; ++ } ++ } ++ ++ /* AuDbgDentry(d); */ ++ btop = au_dbtop(d); ++ bbot = au_dbbot(d); ++ if (btop <= bindex ++ && bindex <= bbot ++ && au_h_dptr(d, bindex) ++ && au_test_dbusy(d, btop, bbot)) { ++ err = -EBUSY; ++ AuVerbose(verbose, "busy %pd\n", d); ++ AuDbgDentry(d); ++ } ++ di_read_unlock(d, AuLock_IR); ++ } ++ } ++ ++out_dpages: ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++static int test_inode_busy(struct super_block *sb, aufs_bindex_t bindex, ++ unsigned int sigen, const unsigned int verbose) ++{ ++ int err; ++ unsigned long long max, ull; ++ struct inode *i, **array; ++ aufs_bindex_t btop, bbot; ++ ++ array = au_iarray_alloc(sb, &max); ++ err = PTR_ERR(array); ++ if (IS_ERR(array)) ++ goto out; ++ ++ err = 0; ++ AuDbg("b%d\n", bindex); ++ for (ull = 0; !err && ull < max; ull++) { ++ i = array[ull]; ++ if (unlikely(!i)) ++ break; ++ if (i->i_ino == AUFS_ROOT_INO) ++ continue; ++ ++ /* AuDbgInode(i); */ ++ if (au_iigen(i, NULL) == sigen) ++ ii_read_lock_child(i); ++ else { ++ ii_write_lock_child(i); ++ err = au_refresh_hinode_self(i); ++ au_iigen_dec(i); ++ if (!err) ++ ii_downgrade_lock(i); ++ else { ++ ii_write_unlock(i); ++ break; ++ } ++ } ++ ++ btop = au_ibtop(i); ++ bbot = au_ibbot(i); ++ if (btop <= bindex ++ && bindex <= bbot ++ && au_h_iptr(i, bindex) ++ && au_test_ibusy(i, btop, bbot)) { ++ err = -EBUSY; ++ AuVerbose(verbose, "busy i%lu\n", i->i_ino); ++ AuDbgInode(i); ++ } ++ ii_read_unlock(i); ++ } ++ au_iarray_free(array, max); ++ ++out: ++ return err; ++} ++ ++static int test_children_busy(struct dentry *root, aufs_bindex_t bindex, ++ const unsigned int verbose) ++{ ++ int err; ++ unsigned int sigen; ++ ++ sigen = au_sigen(root->d_sb); ++ DiMustNoWaiters(root); ++ IiMustNoWaiters(d_inode(root)); ++ di_write_unlock(root); ++ err = test_dentry_busy(root, bindex, sigen, verbose); ++ if (!err) ++ err = test_inode_busy(root->d_sb, bindex, sigen, verbose); ++ di_write_lock_child(root); /* aufs_write_lock() calls ..._child() */ ++ ++ return err; ++} ++ ++static int test_dir_busy(struct file *file, aufs_bindex_t br_id, ++ struct file **to_free, int *idx) ++{ ++ int err; ++ unsigned char matched, root; ++ aufs_bindex_t bindex, bbot; ++ struct au_fidir *fidir; ++ struct au_hfile *hfile; ++ ++ err = 0; ++ root = IS_ROOT(file->f_path.dentry); ++ if (root) { ++ get_file(file); ++ to_free[*idx] = file; ++ (*idx)++; ++ goto out; ++ } ++ ++ matched = 0; ++ fidir = au_fi(file)->fi_hdir; ++ AuDebugOn(!fidir); ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); bindex <= bbot; bindex++) { ++ hfile = fidir->fd_hfile + bindex; ++ if (!hfile->hf_file) ++ continue; ++ ++ if (hfile->hf_br->br_id == br_id) { ++ matched = 1; ++ break; ++ } ++ } ++ if (matched) ++ err = -EBUSY; ++ ++out: ++ return err; ++} ++ ++static int test_file_busy(struct super_block *sb, aufs_bindex_t br_id, ++ struct file **to_free, int opened) ++{ ++ int err, idx; ++ unsigned long long ull, max; ++ aufs_bindex_t btop; ++ struct file *file, **array; ++ struct dentry *root; ++ struct au_hfile *hfile; ++ ++ array = au_farray_alloc(sb, &max); ++ err = PTR_ERR(array); ++ if (IS_ERR(array)) ++ goto out; ++ ++ err = 0; ++ idx = 0; ++ root = sb->s_root; ++ di_write_unlock(root); ++ for (ull = 0; ull < max; ull++) { ++ file = array[ull]; ++ if (unlikely(!file)) ++ break; ++ ++ /* AuDbg("%pD\n", file); */ ++ fi_read_lock(file); ++ btop = au_fbtop(file); ++ if (!d_is_dir(file->f_path.dentry)) { ++ hfile = &au_fi(file)->fi_htop; ++ if (hfile->hf_br->br_id == br_id) ++ err = -EBUSY; ++ } else ++ err = test_dir_busy(file, br_id, to_free, &idx); ++ fi_read_unlock(file); ++ if (unlikely(err)) ++ break; ++ } ++ di_write_lock_child(root); ++ au_farray_free(array, max); ++ AuDebugOn(idx > opened); ++ ++out: ++ return err; ++} ++ ++static void br_del_file(struct file **to_free, unsigned long long opened, ++ aufs_bindex_t br_id) ++{ ++ unsigned long long ull; ++ aufs_bindex_t bindex, btop, bbot, bfound; ++ struct file *file; ++ struct au_fidir *fidir; ++ struct au_hfile *hfile; ++ ++ for (ull = 0; ull < opened; ull++) { ++ file = to_free[ull]; ++ if (unlikely(!file)) ++ break; ++ ++ /* AuDbg("%pD\n", file); */ ++ AuDebugOn(!d_is_dir(file->f_path.dentry)); ++ bfound = -1; ++ fidir = au_fi(file)->fi_hdir; ++ AuDebugOn(!fidir); ++ fi_write_lock(file); ++ btop = au_fbtop(file); ++ bbot = au_fbbot_dir(file); ++ for (bindex = btop; bindex <= bbot; bindex++) { ++ hfile = fidir->fd_hfile + bindex; ++ if (!hfile->hf_file) ++ continue; ++ ++ if (hfile->hf_br->br_id == br_id) { ++ bfound = bindex; ++ break; ++ } ++ } ++ AuDebugOn(bfound < 0); ++ au_set_h_fptr(file, bfound, NULL); ++ if (bfound == btop) { ++ for (btop++; btop <= bbot; btop++) ++ if (au_hf_dir(file, btop)) { ++ au_set_fbtop(file, btop); ++ break; ++ } ++ } ++ fi_write_unlock(file); ++ } ++} ++ ++static void au_br_do_del_brp(struct au_sbinfo *sbinfo, ++ const aufs_bindex_t bindex, ++ const aufs_bindex_t bbot) ++{ ++ struct au_branch **brp, **p; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ brp = sbinfo->si_branch + bindex; ++ if (bindex < bbot) ++ memmove(brp, brp + 1, sizeof(*brp) * (bbot - bindex)); ++ sbinfo->si_branch[0 + bbot] = NULL; ++ sbinfo->si_bbot--; ++ ++ p = au_krealloc(sbinfo->si_branch, sizeof(*p) * bbot, AuGFP_SBILIST, ++ /*may_shrink*/1); ++ if (p) ++ sbinfo->si_branch = p; ++ /* harmless error */ ++} ++ ++static void au_br_do_del_hdp(struct au_dinfo *dinfo, const aufs_bindex_t bindex, ++ const aufs_bindex_t bbot) ++{ ++ struct au_hdentry *hdp, *p; ++ ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ hdp = au_hdentry(dinfo, bindex); ++ if (bindex < bbot) ++ memmove(hdp, hdp + 1, sizeof(*hdp) * (bbot - bindex)); ++ /* au_h_dentry_init(au_hdentry(dinfo, bbot); */ ++ dinfo->di_bbot--; ++ ++ p = au_krealloc(dinfo->di_hdentry, sizeof(*p) * bbot, AuGFP_SBILIST, ++ /*may_shrink*/1); ++ if (p) ++ dinfo->di_hdentry = p; ++ /* harmless error */ ++} ++ ++static void au_br_do_del_hip(struct au_iinfo *iinfo, const aufs_bindex_t bindex, ++ const aufs_bindex_t bbot) ++{ ++ struct au_hinode *hip, *p; ++ ++ AuRwMustWriteLock(&iinfo->ii_rwsem); ++ ++ hip = au_hinode(iinfo, bindex); ++ if (bindex < bbot) ++ memmove(hip, hip + 1, sizeof(*hip) * (bbot - bindex)); ++ /* au_hinode_init(au_hinode(iinfo, bbot)); */ ++ iinfo->ii_bbot--; ++ ++ p = au_krealloc(iinfo->ii_hinode, sizeof(*p) * bbot, AuGFP_SBILIST, ++ /*may_shrink*/1); ++ if (p) ++ iinfo->ii_hinode = p; ++ /* harmless error */ ++} ++ ++static void au_br_do_del(struct super_block *sb, aufs_bindex_t bindex, ++ struct au_branch *br) ++{ ++ aufs_bindex_t bbot; ++ struct au_sbinfo *sbinfo; ++ struct dentry *root, *h_root; ++ struct inode *inode, *h_inode; ++ struct au_hinode *hinode; ++ ++ SiMustWriteLock(sb); ++ ++ root = sb->s_root; ++ inode = d_inode(root); ++ sbinfo = au_sbi(sb); ++ bbot = sbinfo->si_bbot; ++ ++ h_root = au_h_dptr(root, bindex); ++ hinode = au_hi(inode, bindex); ++ h_inode = au_igrab(hinode->hi_inode); ++ au_hiput(hinode); ++ ++ au_sbilist_lock(); ++ au_br_do_del_brp(sbinfo, bindex, bbot); ++ au_br_do_del_hdp(au_di(root), bindex, bbot); ++ au_br_do_del_hip(au_ii(inode), bindex, bbot); ++ au_sbilist_unlock(); ++ ++ /* ignore an error */ ++ au_dr_br_fin(sb, br); /* always, regardless the mount option */ ++ ++ dput(h_root); ++ iput(h_inode); ++ au_br_do_free(br); ++} ++ ++static unsigned long long empty_cb(struct super_block *sb, void *array, ++ unsigned long long max, void *arg) ++{ ++ return max; ++} ++ ++int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount) ++{ ++ int err, rerr, i; ++ unsigned long long opened; ++ unsigned int mnt_flags; ++ aufs_bindex_t bindex, bbot, br_id; ++ unsigned char do_wh, verbose; ++ struct au_branch *br; ++ struct au_wbr *wbr; ++ struct dentry *root; ++ struct file **to_free; ++ ++ err = 0; ++ opened = 0; ++ to_free = NULL; ++ root = sb->s_root; ++ bindex = au_find_dbindex(root, del->h_path.dentry); ++ if (bindex < 0) { ++ if (remount) ++ goto out; /* success */ ++ err = -ENOENT; ++ pr_err("%s no such branch\n", del->pathname); ++ goto out; ++ } ++ AuDbg("bindex b%d\n", bindex); ++ ++ err = -EBUSY; ++ mnt_flags = au_mntflags(sb); ++ verbose = !!au_opt_test(mnt_flags, VERBOSE); ++ bbot = au_sbbot(sb); ++ if (unlikely(!bbot)) { ++ AuVerbose(verbose, "no more branches left\n"); ++ goto out; ++ } ++ ++ br = au_sbr(sb, bindex); ++ AuDebugOn(!path_equal(&br->br_path, &del->h_path)); ++ if (unlikely(au_lcnt_read(&br->br_count, /*do_rev*/1))) { ++ AuVerbose(verbose, "br %pd2 is busy now\n", del->h_path.dentry); ++ goto out; ++ } ++ ++ br_id = br->br_id; ++ opened = au_lcnt_read(&br->br_nfiles, /*do_rev*/1); ++ if (unlikely(opened)) { ++ to_free = au_array_alloc(&opened, empty_cb, sb, NULL); ++ err = PTR_ERR(to_free); ++ if (IS_ERR(to_free)) ++ goto out; ++ ++ err = test_file_busy(sb, br_id, to_free, opened); ++ if (unlikely(err)) { ++ AuVerbose(verbose, "%llu file(s) opened\n", opened); ++ goto out; ++ } ++ } ++ ++ wbr = br->br_wbr; ++ do_wh = wbr && (wbr->wbr_whbase || wbr->wbr_plink || wbr->wbr_orph); ++ if (do_wh) { ++ /* instead of WbrWhMustWriteLock(wbr) */ ++ SiMustWriteLock(sb); ++ for (i = 0; i < AuBrWh_Last; i++) { ++ dput(wbr->wbr_wh[i]); ++ wbr->wbr_wh[i] = NULL; ++ } ++ } ++ ++ err = test_children_busy(root, bindex, verbose); ++ if (unlikely(err)) { ++ if (do_wh) ++ goto out_wh; ++ goto out; ++ } ++ ++ err = 0; ++ if (to_free) { ++ /* ++ * now we confirmed the branch is deletable. ++ * let's free the remaining opened dirs on the branch. ++ */ ++ di_write_unlock(root); ++ br_del_file(to_free, opened, br_id); ++ di_write_lock_child(root); ++ } ++ ++ sysaufs_brs_del(sb, bindex); /* remove successors */ ++ dbgaufs_xino_del(br); /* remove one */ ++ au_br_do_del(sb, bindex, br); ++ sysaufs_brs_add(sb, bindex); /* append successors */ ++ dbgaufs_brs_add(sb, bindex, /*topdown*/1); /* rename successors */ ++ ++ if (!bindex) { ++ au_cpup_attr_all(d_inode(root), /*force*/1); ++ sb->s_maxbytes = au_sbr_sb(sb, 0)->s_maxbytes; ++ } else ++ au_sub_nlink(d_inode(root), d_inode(del->h_path.dentry)); ++ if (au_opt_test(mnt_flags, PLINK)) ++ au_plink_half_refresh(sb, br_id); ++ ++ goto out; /* success */ ++ ++out_wh: ++ /* revert */ ++ rerr = au_br_init_wh(sb, br, br->br_perm); ++ if (rerr) ++ pr_warn("failed re-creating base whiteout, %s. (%d)\n", ++ del->pathname, rerr); ++out: ++ if (to_free) ++ au_farray_free(to_free, opened); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_ibusy(struct super_block *sb, struct aufs_ibusy __user *arg) ++{ ++ int err; ++ aufs_bindex_t btop, bbot; ++ struct aufs_ibusy ibusy; ++ struct inode *inode, *h_inode; ++ ++ err = -EPERM; ++ if (unlikely(!capable(CAP_SYS_ADMIN))) ++ goto out; ++ ++ err = copy_from_user(&ibusy, arg, sizeof(ibusy)); ++ if (!err) ++ /* VERIFY_WRITE */ ++ err = !access_ok(&arg->h_ino, sizeof(arg->h_ino)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out; ++ } ++ ++ err = -EINVAL; ++ si_read_lock(sb, AuLock_FLUSH); ++ if (unlikely(ibusy.bindex < 0 || ibusy.bindex > au_sbbot(sb))) ++ goto out_unlock; ++ ++ err = 0; ++ ibusy.h_ino = 0; /* invalid */ ++ inode = ilookup(sb, ibusy.ino); ++ if (!inode ++ || inode->i_ino == AUFS_ROOT_INO ++ || au_is_bad_inode(inode)) ++ goto out_unlock; ++ ++ ii_read_lock_child(inode); ++ btop = au_ibtop(inode); ++ bbot = au_ibbot(inode); ++ if (btop <= ibusy.bindex && ibusy.bindex <= bbot) { ++ h_inode = au_h_iptr(inode, ibusy.bindex); ++ if (h_inode && au_test_ibusy(inode, btop, bbot)) ++ ibusy.h_ino = h_inode->i_ino; ++ } ++ ii_read_unlock(inode); ++ iput(inode); ++ ++out_unlock: ++ si_read_unlock(sb); ++ if (!err) { ++ err = __put_user(ibusy.h_ino, &arg->h_ino); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ } ++ } ++out: ++ return err; ++} ++ ++long au_ibusy_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_ibusy(file->f_path.dentry->d_sb, (void __user *)arg); ++} ++ ++#ifdef CONFIG_COMPAT ++long au_ibusy_compat_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_ibusy(file->f_path.dentry->d_sb, compat_ptr(arg)); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * change a branch permission ++ */ ++ ++static void au_warn_ima(void) ++{ ++#ifdef CONFIG_IMA ++ /* since it doesn't support mark_files_ro() */ ++ AuWarn1("RW -> RO makes IMA to produce wrong message\n"); ++#endif ++} ++ ++static int do_need_sigen_inc(int a, int b) ++{ ++ return au_br_whable(a) && !au_br_whable(b); ++} ++ ++static int need_sigen_inc(int old, int new) ++{ ++ return do_need_sigen_inc(old, new) ++ || do_need_sigen_inc(new, old); ++} ++ ++static int au_br_mod_files_ro(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ int err, do_warn; ++ unsigned int mnt_flags; ++ unsigned long long ull, max; ++ aufs_bindex_t br_id; ++ unsigned char verbose, writer; ++ struct file *file, *hf, **array; ++ struct au_hfile *hfile; ++ struct inode *h_inode; ++ ++ mnt_flags = au_mntflags(sb); ++ verbose = !!au_opt_test(mnt_flags, VERBOSE); ++ ++ array = au_farray_alloc(sb, &max); ++ err = PTR_ERR(array); ++ if (IS_ERR(array)) ++ goto out; ++ ++ do_warn = 0; ++ br_id = au_sbr_id(sb, bindex); ++ for (ull = 0; ull < max; ull++) { ++ file = array[ull]; ++ if (unlikely(!file)) ++ break; ++ ++ /* AuDbg("%pD\n", file); */ ++ fi_read_lock(file); ++ if (unlikely(au_test_mmapped(file))) { ++ err = -EBUSY; ++ AuVerbose(verbose, "mmapped %pD\n", file); ++ AuDbgFile(file); ++ FiMustNoWaiters(file); ++ fi_read_unlock(file); ++ goto out_array; ++ } ++ ++ hfile = &au_fi(file)->fi_htop; ++ hf = hfile->hf_file; ++ if (!d_is_reg(file->f_path.dentry) ++ || !(file->f_mode & FMODE_WRITE) ++ || hfile->hf_br->br_id != br_id ++ || !(hf->f_mode & FMODE_WRITE)) ++ array[ull] = NULL; ++ else { ++ do_warn = 1; ++ get_file(file); ++ } ++ ++ FiMustNoWaiters(file); ++ fi_read_unlock(file); ++ fput(file); ++ } ++ ++ err = 0; ++ if (do_warn) ++ au_warn_ima(); ++ ++ for (ull = 0; ull < max; ull++) { ++ file = array[ull]; ++ if (!file) ++ continue; ++ ++ /* todo: already flushed? */ ++ /* ++ * fs/super.c:mark_files_ro() is gone, but aufs keeps its ++ * approach which resets f_mode and calls mnt_drop_write() and ++ * file_release_write() for each file, because the branch ++ * attribute in aufs world is totally different from the native ++ * fs rw/ro mode. ++ */ ++ /* fi_read_lock(file); */ ++ hfile = &au_fi(file)->fi_htop; ++ hf = hfile->hf_file; ++ /* fi_read_unlock(file); */ ++ spin_lock(&hf->f_lock); ++ writer = !!(hf->f_mode & FMODE_WRITER); ++ hf->f_mode &= ~(FMODE_WRITE | FMODE_WRITER); ++ spin_unlock(&hf->f_lock); ++ if (writer) { ++ h_inode = file_inode(hf); ++ if (hf->f_mode & FMODE_READ) ++ i_readcount_inc(h_inode); ++ put_write_access(h_inode); ++ __mnt_drop_write(hf->f_path.mnt); ++ } ++ } ++ ++out_array: ++ au_farray_free(array, max); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount, ++ int *do_refresh) ++{ ++ int err, rerr; ++ aufs_bindex_t bindex; ++ struct dentry *root; ++ struct au_branch *br; ++ struct au_br_fhsm *bf; ++ ++ root = sb->s_root; ++ bindex = au_find_dbindex(root, mod->h_root); ++ if (bindex < 0) { ++ if (remount) ++ return 0; /* success */ ++ err = -ENOENT; ++ pr_err("%s no such branch\n", mod->path); ++ goto out; ++ } ++ AuDbg("bindex b%d\n", bindex); ++ ++ err = test_br(d_inode(mod->h_root), mod->perm, mod->path); ++ if (unlikely(err)) ++ goto out; ++ ++ br = au_sbr(sb, bindex); ++ AuDebugOn(mod->h_root != au_br_dentry(br)); ++ if (br->br_perm == mod->perm) ++ return 0; /* success */ ++ ++ /* pre-allocate for non-fhsm --> fhsm */ ++ bf = NULL; ++ if (!au_br_fhsm(br->br_perm) && au_br_fhsm(mod->perm)) { ++ err = au_fhsm_br_alloc(br); ++ if (unlikely(err)) ++ goto out; ++ bf = br->br_fhsm; ++ br->br_fhsm = NULL; ++ } ++ ++ if (au_br_writable(br->br_perm)) { ++ /* remove whiteout base */ ++ err = au_br_init_wh(sb, br, mod->perm); ++ if (unlikely(err)) ++ goto out_bf; ++ ++ if (!au_br_writable(mod->perm)) { ++ /* rw --> ro, file might be mmapped */ ++ DiMustNoWaiters(root); ++ IiMustNoWaiters(d_inode(root)); ++ di_write_unlock(root); ++ err = au_br_mod_files_ro(sb, bindex); ++ /* aufs_write_lock() calls ..._child() */ ++ di_write_lock_child(root); ++ ++ if (unlikely(err)) { ++ rerr = -ENOMEM; ++ br->br_wbr = kzalloc(sizeof(*br->br_wbr), ++ GFP_NOFS); ++ if (br->br_wbr) ++ rerr = au_wbr_init(br, sb, br->br_perm); ++ if (unlikely(rerr)) { ++ AuIOErr("nested error %d (%d)\n", ++ rerr, err); ++ br->br_perm = mod->perm; ++ } ++ } ++ } ++ } else if (au_br_writable(mod->perm)) { ++ /* ro --> rw */ ++ err = -ENOMEM; ++ br->br_wbr = kzalloc(sizeof(*br->br_wbr), GFP_NOFS); ++ if (br->br_wbr) { ++ err = au_wbr_init(br, sb, mod->perm); ++ if (unlikely(err)) { ++ au_kfree_rcu(br->br_wbr); ++ br->br_wbr = NULL; ++ } ++ } ++ } ++ if (unlikely(err)) ++ goto out_bf; ++ ++ if (au_br_fhsm(br->br_perm)) { ++ if (!au_br_fhsm(mod->perm)) { ++ /* fhsm --> non-fhsm */ ++ au_br_fhsm_fin(br->br_fhsm); ++ au_kfree_rcu(br->br_fhsm); ++ br->br_fhsm = NULL; ++ } ++ } else if (au_br_fhsm(mod->perm)) ++ /* non-fhsm --> fhsm */ ++ br->br_fhsm = bf; ++ ++ *do_refresh |= need_sigen_inc(br->br_perm, mod->perm); ++ br->br_perm = mod->perm; ++ goto out; /* success */ ++ ++out_bf: ++ au_kfree_try_rcu(bf); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_br_stfs(struct au_branch *br, struct aufs_stfs *stfs) ++{ ++ int err; ++ struct kstatfs kstfs; ++ ++ err = vfs_statfs(&br->br_path, &kstfs); ++ if (!err) { ++ stfs->f_blocks = kstfs.f_blocks; ++ stfs->f_bavail = kstfs.f_bavail; ++ stfs->f_files = kstfs.f_files; ++ stfs->f_ffree = kstfs.f_ffree; ++ } ++ ++ return err; ++} +diff -Naur null/fs/aufs/branch.h linux-5.15.36/fs/aufs/branch.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/branch.h 2022-05-10 16:51:39.866744220 +0300 +@@ -0,0 +1,375 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * branch filesystems and xino for them ++ */ ++ ++#ifndef __AUFS_BRANCH_H__ ++#define __AUFS_BRANCH_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "dirren.h" ++#include "dynop.h" ++#include "lcnt.h" ++#include "rwsem.h" ++#include "super.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* a xino file */ ++struct au_xino { ++ struct file **xi_file; ++ unsigned int xi_nfile; ++ ++ struct { ++ spinlock_t spin; ++ ino_t *array; ++ int total; ++ /* reserved for future use */ ++ /* unsigned long *bitmap; */ ++ wait_queue_head_t wqh; ++ } xi_nondir; ++ ++ struct mutex xi_mtx; /* protects xi_file array */ ++ struct hlist_bl_head xi_writing; ++ ++ atomic_t xi_truncating; ++ ++ struct kref xi_kref; ++}; ++ ++/* File-based Hierarchical Storage Management */ ++struct au_br_fhsm { ++#ifdef CONFIG_AUFS_FHSM ++ struct mutex bf_lock; ++ unsigned long bf_jiffy; ++ struct aufs_stfs bf_stfs; ++ int bf_readable; ++#endif ++}; ++ ++/* members for writable branch only */ ++enum {AuBrWh_BASE, AuBrWh_PLINK, AuBrWh_ORPH, AuBrWh_Last}; ++struct au_wbr { ++ struct au_rwsem wbr_wh_rwsem; ++ struct dentry *wbr_wh[AuBrWh_Last]; ++ atomic_t wbr_wh_running; ++#define wbr_whbase wbr_wh[AuBrWh_BASE] /* whiteout base */ ++#define wbr_plink wbr_wh[AuBrWh_PLINK] /* pseudo-link dir */ ++#define wbr_orph wbr_wh[AuBrWh_ORPH] /* dir for orphans */ ++ ++ /* mfs mode */ ++ unsigned long long wbr_bytes; ++}; ++ ++/* ext2 has 3 types of operations at least, ext3 has 4 */ ++#define AuBrDynOp (AuDyLast * 4) ++ ++#ifdef CONFIG_AUFS_HFSNOTIFY ++/* support for asynchronous destruction */ ++struct au_br_hfsnotify { ++ struct fsnotify_group *hfsn_group; ++}; ++#endif ++ ++/* sysfs entries */ ++struct au_brsysfs { ++ char name[16]; ++ struct attribute attr; ++}; ++ ++enum { ++ AuBrSysfs_BR, ++ AuBrSysfs_BRID, ++ AuBrSysfs_Last ++}; ++ ++/* protected by superblock rwsem */ ++struct au_branch { ++ struct au_xino *br_xino; ++ ++ aufs_bindex_t br_id; ++ ++ int br_perm; ++ struct path br_path; ++ spinlock_t br_dykey_lock; ++ struct au_dykey *br_dykey[AuBrDynOp]; ++ au_lcnt_t br_nfiles; /* opened files */ ++ au_lcnt_t br_count; /* in-use for other */ ++ ++ struct au_wbr *br_wbr; ++ struct au_br_fhsm *br_fhsm; ++ ++#ifdef CONFIG_AUFS_HFSNOTIFY ++ struct au_br_hfsnotify *br_hfsn; ++#endif ++ ++#ifdef CONFIG_SYSFS ++ /* entries under sysfs per mount-point */ ++ struct au_brsysfs br_sysfs[AuBrSysfs_Last]; ++#endif ++ ++#ifdef CONFIG_DEBUG_FS ++ struct dentry *br_dbgaufs; /* xino */ ++#endif ++ ++ struct au_dr_br br_dirren; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct vfsmount *au_br_mnt(struct au_branch *br) ++{ ++ return br->br_path.mnt; ++} ++ ++static inline struct dentry *au_br_dentry(struct au_branch *br) ++{ ++ return br->br_path.dentry; ++} ++ ++static inline struct user_namespace *au_br_userns(struct au_branch *br) ++{ ++ return mnt_user_ns(br->br_path.mnt); ++} ++ ++static inline struct super_block *au_br_sb(struct au_branch *br) ++{ ++ return au_br_mnt(br)->mnt_sb; ++} ++ ++static inline int au_br_rdonly(struct au_branch *br) ++{ ++ return (sb_rdonly(au_br_sb(br)) ++ || !au_br_writable(br->br_perm)) ++ ? -EROFS : 0; ++} ++ ++static inline int au_br_hnotifyable(int brperm __maybe_unused) ++{ ++#ifdef CONFIG_AUFS_HNOTIFY ++ return !(brperm & AuBrPerm_RR); ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_br_test_oflag(int oflag, struct au_branch *br) ++{ ++ int err, exec_flag; ++ ++ err = 0; ++ exec_flag = oflag & __FMODE_EXEC; ++ if (unlikely(exec_flag && path_noexec(&br->br_path))) ++ err = -EACCES; ++ ++ return err; ++} ++ ++static inline void au_xino_get(struct au_branch *br) ++{ ++ struct au_xino *xi; ++ ++ xi = br->br_xino; ++ if (xi) ++ kref_get(&xi->xi_kref); ++} ++ ++static inline int au_xino_count(struct au_branch *br) ++{ ++ int v; ++ struct au_xino *xi; ++ ++ v = 0; ++ xi = br->br_xino; ++ if (xi) ++ v = kref_read(&xi->xi_kref); ++ ++ return v; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* branch.c */ ++struct au_sbinfo; ++void au_br_free(struct au_sbinfo *sinfo); ++int au_br_index(struct super_block *sb, aufs_bindex_t br_id); ++struct au_opt_add; ++int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount); ++struct au_opt_del; ++int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount); ++long au_ibusy_ioctl(struct file *file, unsigned long arg); ++#ifdef CONFIG_COMPAT ++long au_ibusy_compat_ioctl(struct file *file, unsigned long arg); ++#endif ++struct au_opt_mod; ++int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount, ++ int *do_refresh); ++struct aufs_stfs; ++int au_br_stfs(struct au_branch *br, struct aufs_stfs *stfs); ++ ++/* xino.c */ ++static const loff_t au_loff_max = LLONG_MAX; ++ ++aufs_bindex_t au_xi_root(struct super_block *sb, struct dentry *dentry); ++struct file *au_xino_create(struct super_block *sb, char *fpath, int silent, ++ int wbrtop); ++struct file *au_xino_create2(struct super_block *sb, struct path *base, ++ struct file *copy_src); ++struct au_xi_new { ++ struct au_xino *xi; /* switch between xino and xigen */ ++ int idx; ++ struct path *base; ++ struct file *copy_src; ++}; ++struct file *au_xi_new(struct super_block *sb, struct au_xi_new *xinew); ++ ++int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t *ino); ++int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t ino); ++ssize_t xino_fread(struct file *file, void *buf, size_t size, loff_t *pos); ++ssize_t xino_fwrite(struct file *file, void *buf, size_t size, loff_t *pos); ++ ++int au_xib_trunc(struct super_block *sb); ++int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex, int idx_begin); ++ ++struct au_xino *au_xino_alloc(unsigned int nfile); ++int au_xino_put(struct au_branch *br); ++struct file *au_xino_file1(struct au_xino *xi); ++ ++struct au_opt_xino; ++void au_xino_clr(struct super_block *sb); ++int au_xino_set(struct super_block *sb, struct au_opt_xino *xiopt, int remount); ++struct file *au_xino_def(struct super_block *sb); ++int au_xino_init_br(struct super_block *sb, struct au_branch *br, ino_t hino, ++ struct path *base); ++ ++ino_t au_xino_new_ino(struct super_block *sb); ++void au_xino_delete_inode(struct inode *inode, const int unlinked); ++ ++void au_xinondir_leave(struct super_block *sb, aufs_bindex_t bindex, ++ ino_t h_ino, int idx); ++int au_xinondir_enter(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ int *idx); ++ ++int au_xino_path(struct seq_file *seq, struct file *file); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* @idx is signed to accept -1 meaning the first file */ ++static inline struct file *au_xino_file(struct au_xino *xi, int idx) ++{ ++ struct file *file; ++ ++ file = NULL; ++ if (!xi) ++ goto out; ++ ++ if (idx >= 0) { ++ if (idx < xi->xi_nfile) ++ file = xi->xi_file[idx]; ++ } else ++ file = au_xino_file1(xi); ++ ++out: ++ return file; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* Superblock to branch */ ++static inline ++aufs_bindex_t au_sbr_id(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_sbr(sb, bindex)->br_id; ++} ++ ++static inline ++struct vfsmount *au_sbr_mnt(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_br_mnt(au_sbr(sb, bindex)); ++} ++ ++static inline ++struct user_namespace *au_sbr_userns(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_br_userns(au_sbr(sb, bindex)); ++} ++ ++static inline ++struct super_block *au_sbr_sb(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_br_sb(au_sbr(sb, bindex)); ++} ++ ++static inline int au_sbr_perm(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_sbr(sb, bindex)->br_perm; ++} ++ ++static inline int au_sbr_whable(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_br_whable(au_sbr_perm(sb, bindex)); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define wbr_wh_read_lock(wbr) au_rw_read_lock(&(wbr)->wbr_wh_rwsem) ++#define wbr_wh_write_lock(wbr) au_rw_write_lock(&(wbr)->wbr_wh_rwsem) ++#define wbr_wh_read_trylock(wbr) au_rw_read_trylock(&(wbr)->wbr_wh_rwsem) ++#define wbr_wh_write_trylock(wbr) au_rw_write_trylock(&(wbr)->wbr_wh_rwsem) ++/* ++#define wbr_wh_read_trylock_nested(wbr) \ ++ au_rw_read_trylock_nested(&(wbr)->wbr_wh_rwsem) ++#define wbr_wh_write_trylock_nested(wbr) \ ++ au_rw_write_trylock_nested(&(wbr)->wbr_wh_rwsem) ++*/ ++ ++#define wbr_wh_read_unlock(wbr) au_rw_read_unlock(&(wbr)->wbr_wh_rwsem) ++#define wbr_wh_write_unlock(wbr) au_rw_write_unlock(&(wbr)->wbr_wh_rwsem) ++#define wbr_wh_downgrade_lock(wbr) au_rw_dgrade_lock(&(wbr)->wbr_wh_rwsem) ++ ++#define WbrWhMustNoWaiters(wbr) AuRwMustNoWaiters(&(wbr)->wbr_wh_rwsem) ++#define WbrWhMustAnyLock(wbr) AuRwMustAnyLock(&(wbr)->wbr_wh_rwsem) ++#define WbrWhMustWriteLock(wbr) AuRwMustWriteLock(&(wbr)->wbr_wh_rwsem) ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_FHSM ++static inline void au_br_fhsm_init(struct au_br_fhsm *brfhsm) ++{ ++ mutex_init(&brfhsm->bf_lock); ++ brfhsm->bf_jiffy = 0; ++ brfhsm->bf_readable = 0; ++} ++ ++static inline void au_br_fhsm_fin(struct au_br_fhsm *brfhsm) ++{ ++ mutex_destroy(&brfhsm->bf_lock); ++} ++#else ++AuStubVoid(au_br_fhsm_init, struct au_br_fhsm *brfhsm) ++AuStubVoid(au_br_fhsm_fin, struct au_br_fhsm *brfhsm) ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_BRANCH_H__ */ +diff -Naur null/fs/aufs/conf.mk linux-5.15.36/fs/aufs/conf.mk +--- /dev/null ++++ linux-5.15.36/fs/aufs/conf.mk 2022-05-10 16:51:39.867744220 +0300 +@@ -0,0 +1,40 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++AuConfStr = CONFIG_AUFS_FS=${CONFIG_AUFS_FS} ++ ++define AuConf ++ifdef ${1} ++AuConfStr += ${1}=${${1}} ++endif ++endef ++ ++AuConfAll = BRANCH_MAX_127 BRANCH_MAX_511 BRANCH_MAX_1023 BRANCH_MAX_32767 \ ++ SBILIST \ ++ HNOTIFY HFSNOTIFY \ ++ EXPORT INO_T_64 \ ++ XATTR \ ++ FHSM \ ++ RDU \ ++ DIRREN \ ++ SHWH \ ++ BR_RAMFS \ ++ BR_FUSE POLL \ ++ BR_HFSPLUS \ ++ BDEV_LOOP \ ++ DEBUG MAGIC_SYSRQ ++$(foreach i, ${AuConfAll}, \ ++ $(eval $(call AuConf,CONFIG_AUFS_${i}))) ++ ++AuConfName = ${obj}/conf.str ++${AuConfName}.tmp: FORCE ++ @echo ${AuConfStr} | tr ' ' '\n' | sed -e 's/^/"/' -e 's/$$/\\n"/' > $@ ++${AuConfName}: ${AuConfName}.tmp ++ @diff -q $< $@ > /dev/null 2>&1 || { \ ++ echo ' GEN ' $@; \ ++ cp -p $< $@; \ ++ } ++FORCE: ++clean-files += ${AuConfName} ${AuConfName}.tmp ++${obj}/sysfs.o: ${AuConfName} ++ ++-include ${srctree}/${src}/conf_priv.mk +diff -Naur null/fs/aufs/cpup.c linux-5.15.36/fs/aufs/cpup.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/cpup.c 2022-05-10 16:51:39.867744220 +0300 +@@ -0,0 +1,1459 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * copy-up functions, see wbr_policy.c for copy-down ++ */ ++ ++#include ++#include ++#include ++#include "aufs.h" ++ ++void au_cpup_attr_flags(struct inode *dst, unsigned int iflags) ++{ ++ const unsigned int mask = S_DEAD | S_SWAPFILE | S_PRIVATE ++ | S_NOATIME | S_NOCMTIME | S_AUTOMOUNT; ++ ++ BUILD_BUG_ON(sizeof(iflags) != sizeof(dst->i_flags)); ++ ++ dst->i_flags |= iflags & ~mask; ++ if (au_test_fs_notime(dst->i_sb)) ++ dst->i_flags |= S_NOATIME | S_NOCMTIME; ++} ++ ++void au_cpup_attr_timesizes(struct inode *inode) ++{ ++ struct inode *h_inode; ++ ++ h_inode = au_h_iptr(inode, au_ibtop(inode)); ++ fsstack_copy_attr_times(inode, h_inode); ++ fsstack_copy_inode_size(inode, h_inode); ++} ++ ++void au_cpup_attr_nlink(struct inode *inode, int force) ++{ ++ struct inode *h_inode; ++ struct super_block *sb; ++ aufs_bindex_t bindex, bbot; ++ ++ sb = inode->i_sb; ++ bindex = au_ibtop(inode); ++ h_inode = au_h_iptr(inode, bindex); ++ if (!force ++ && !S_ISDIR(h_inode->i_mode) ++ && au_opt_test(au_mntflags(sb), PLINK) ++ && au_plink_test(inode)) ++ return; ++ ++ /* ++ * 0 can happen in revalidating. ++ * h_inode->i_mutex may not be held here, but it is harmless since once ++ * i_nlink reaches 0, it will never become positive except O_TMPFILE ++ * case. ++ * todo: O_TMPFILE+linkat(AT_SYMLINK_FOLLOW) bypassing aufs may cause ++ * the incorrect link count. ++ */ ++ set_nlink(inode, h_inode->i_nlink); ++ ++ /* ++ * fewer nlink makes find(1) noisy, but larger nlink doesn't. ++ * it may includes whplink directory. ++ */ ++ if (S_ISDIR(h_inode->i_mode)) { ++ bbot = au_ibbot(inode); ++ for (bindex++; bindex <= bbot; bindex++) { ++ h_inode = au_h_iptr(inode, bindex); ++ if (h_inode) ++ au_add_nlink(inode, h_inode); ++ } ++ } ++} ++ ++void au_cpup_attr_changeable(struct inode *inode) ++{ ++ struct inode *h_inode; ++ ++ h_inode = au_h_iptr(inode, au_ibtop(inode)); ++ inode->i_mode = h_inode->i_mode; ++ inode->i_uid = h_inode->i_uid; ++ inode->i_gid = h_inode->i_gid; ++ au_cpup_attr_timesizes(inode); ++ au_cpup_attr_flags(inode, h_inode->i_flags); ++} ++ ++void au_cpup_igen(struct inode *inode, struct inode *h_inode) ++{ ++ struct au_iinfo *iinfo = au_ii(inode); ++ ++ IiMustWriteLock(inode); ++ ++ iinfo->ii_higen = h_inode->i_generation; ++ iinfo->ii_hsb1 = h_inode->i_sb; ++} ++ ++void au_cpup_attr_all(struct inode *inode, int force) ++{ ++ struct inode *h_inode; ++ ++ h_inode = au_h_iptr(inode, au_ibtop(inode)); ++ au_cpup_attr_changeable(inode); ++ if (inode->i_nlink > 0) ++ au_cpup_attr_nlink(inode, force); ++ inode->i_rdev = h_inode->i_rdev; ++ inode->i_blkbits = h_inode->i_blkbits; ++ au_cpup_igen(inode, h_inode); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* Note: dt_dentry and dt_h_dentry are not dget/dput-ed */ ++ ++/* keep the timestamps of the parent dir when cpup */ ++void au_dtime_store(struct au_dtime *dt, struct dentry *dentry, ++ struct path *h_path) ++{ ++ struct inode *h_inode; ++ ++ dt->dt_dentry = dentry; ++ dt->dt_h_path = *h_path; ++ h_inode = d_inode(h_path->dentry); ++ dt->dt_atime = h_inode->i_atime; ++ dt->dt_mtime = h_inode->i_mtime; ++ /* smp_mb(); */ ++} ++ ++void au_dtime_revert(struct au_dtime *dt) ++{ ++ struct iattr attr; ++ int err; ++ ++ attr.ia_atime = dt->dt_atime; ++ attr.ia_mtime = dt->dt_mtime; ++ attr.ia_valid = ATTR_FORCE | ATTR_MTIME | ATTR_MTIME_SET ++ | ATTR_ATIME | ATTR_ATIME_SET; ++ ++ /* no delegation since this is a directory */ ++ err = vfsub_notify_change(&dt->dt_h_path, &attr, /*delegated*/NULL); ++ if (unlikely(err)) ++ pr_warn("restoring timestamps failed(%d). ignored\n", err); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* internal use only */ ++struct au_cpup_reg_attr { ++ int valid; ++ struct kstat st; ++ unsigned int iflags; /* inode->i_flags */ ++}; ++ ++static noinline_for_stack ++int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct path *h_src, ++ struct au_cpup_reg_attr *h_src_attr) ++{ ++ int err, sbits, icex; ++ unsigned int mnt_flags; ++ unsigned char verbose; ++ struct iattr ia; ++ struct path h_path; ++ struct inode *h_isrc, *h_idst; ++ struct kstat *h_st; ++ struct au_branch *br; ++ ++ br = au_sbr(dst->d_sb, bindex); ++ h_path.mnt = au_br_mnt(br); ++ h_path.dentry = au_h_dptr(dst, bindex); ++ h_idst = d_inode(h_path.dentry); ++ h_isrc = d_inode(h_src->dentry); ++ ia.ia_valid = ATTR_FORCE | ATTR_UID | ATTR_GID ++ | ATTR_ATIME | ATTR_MTIME ++ | ATTR_ATIME_SET | ATTR_MTIME_SET; ++ if (h_src_attr && h_src_attr->valid) { ++ h_st = &h_src_attr->st; ++ ia.ia_uid = h_st->uid; ++ ia.ia_gid = h_st->gid; ++ ia.ia_atime = h_st->atime; ++ ia.ia_mtime = h_st->mtime; ++ if (h_idst->i_mode != h_st->mode ++ && !S_ISLNK(h_idst->i_mode)) { ++ ia.ia_valid |= ATTR_MODE; ++ ia.ia_mode = h_st->mode; ++ } ++ sbits = !!(h_st->mode & (S_ISUID | S_ISGID)); ++ au_cpup_attr_flags(h_idst, h_src_attr->iflags); ++ } else { ++ ia.ia_uid = h_isrc->i_uid; ++ ia.ia_gid = h_isrc->i_gid; ++ ia.ia_atime = h_isrc->i_atime; ++ ia.ia_mtime = h_isrc->i_mtime; ++ if (h_idst->i_mode != h_isrc->i_mode ++ && !S_ISLNK(h_idst->i_mode)) { ++ ia.ia_valid |= ATTR_MODE; ++ ia.ia_mode = h_isrc->i_mode; ++ } ++ sbits = !!(h_isrc->i_mode & (S_ISUID | S_ISGID)); ++ au_cpup_attr_flags(h_idst, h_isrc->i_flags); ++ } ++ /* no delegation since it is just created */ ++ err = vfsub_notify_change(&h_path, &ia, /*delegated*/NULL); ++ ++ /* is this nfs only? */ ++ if (!err && sbits && au_test_nfs(h_path.dentry->d_sb)) { ++ ia.ia_valid = ATTR_FORCE | ATTR_MODE; ++ ia.ia_mode = h_isrc->i_mode; ++ err = vfsub_notify_change(&h_path, &ia, /*delegated*/NULL); ++ } ++ ++ icex = br->br_perm & AuBrAttr_ICEX; ++ if (!err) { ++ mnt_flags = au_mntflags(dst->d_sb); ++ verbose = !!au_opt_test(mnt_flags, VERBOSE); ++ err = au_cpup_xattr(&h_path, h_src, icex, verbose); ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_copy_file(struct file *dst, struct file *src, loff_t len, ++ char *buf, unsigned long blksize) ++{ ++ int err; ++ size_t sz, rbytes, wbytes; ++ unsigned char all_zero; ++ char *p, *zp; ++ struct inode *h_inode; ++ /* reduce stack usage */ ++ struct iattr *ia; ++ ++ zp = page_address(ZERO_PAGE(0)); ++ if (unlikely(!zp)) ++ return -ENOMEM; /* possible? */ ++ ++ err = 0; ++ all_zero = 0; ++ while (len) { ++ AuDbg("len %lld\n", len); ++ sz = blksize; ++ if (len < blksize) ++ sz = len; ++ ++ rbytes = 0; ++ /* todo: signal_pending? */ ++ while (!rbytes || err == -EAGAIN || err == -EINTR) { ++ rbytes = vfsub_read_k(src, buf, sz, &src->f_pos); ++ err = rbytes; ++ } ++ if (unlikely(err < 0)) ++ break; ++ ++ all_zero = 0; ++ if (len >= rbytes && rbytes == blksize) ++ all_zero = !memcmp(buf, zp, rbytes); ++ if (!all_zero) { ++ wbytes = rbytes; ++ p = buf; ++ while (wbytes) { ++ size_t b; ++ ++ b = vfsub_write_k(dst, p, wbytes, &dst->f_pos); ++ err = b; ++ /* todo: signal_pending? */ ++ if (unlikely(err == -EAGAIN || err == -EINTR)) ++ continue; ++ if (unlikely(err < 0)) ++ break; ++ wbytes -= b; ++ p += b; ++ } ++ if (unlikely(err < 0)) ++ break; ++ } else { ++ loff_t res; ++ ++ AuLabel(hole); ++ res = vfsub_llseek(dst, rbytes, SEEK_CUR); ++ err = res; ++ if (unlikely(res < 0)) ++ break; ++ } ++ len -= rbytes; ++ err = 0; ++ } ++ ++ /* the last block may be a hole */ ++ if (!err && all_zero) { ++ AuLabel(last hole); ++ ++ err = 1; ++ if (au_test_nfs(dst->f_path.dentry->d_sb)) { ++ /* nfs requires this step to make last hole */ ++ /* is this only nfs? */ ++ do { ++ /* todo: signal_pending? */ ++ err = vfsub_write_k(dst, "\0", 1, &dst->f_pos); ++ } while (err == -EAGAIN || err == -EINTR); ++ if (err == 1) ++ dst->f_pos--; ++ } ++ ++ if (err == 1) { ++ ia = (void *)buf; ++ ia->ia_size = dst->f_pos; ++ ia->ia_valid = ATTR_SIZE | ATTR_FILE; ++ ia->ia_file = dst; ++ h_inode = file_inode(dst); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD2); ++ /* no delegation since it is just created */ ++ err = vfsub_notify_change(&dst->f_path, ia, ++ /*delegated*/NULL); ++ inode_unlock(h_inode); ++ } ++ } ++ ++ return err; ++} ++ ++int au_copy_file(struct file *dst, struct file *src, loff_t len) ++{ ++ int err; ++ unsigned long blksize; ++ unsigned char do_kfree; ++ char *buf; ++ struct super_block *h_sb; ++ ++ err = -ENOMEM; ++ h_sb = file_inode(dst)->i_sb; ++ blksize = h_sb->s_blocksize; ++ if (!blksize || PAGE_SIZE < blksize) ++ blksize = PAGE_SIZE; ++ AuDbg("blksize %lu\n", blksize); ++ do_kfree = (blksize != PAGE_SIZE && blksize >= sizeof(struct iattr *)); ++ if (do_kfree) ++ buf = kmalloc(blksize, GFP_NOFS); ++ else ++ buf = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!buf)) ++ goto out; ++ ++ if (len > (1 << 22)) ++ AuDbg("copying a large file %lld\n", (long long)len); ++ ++ src->f_pos = 0; ++ dst->f_pos = 0; ++ err = au_do_copy_file(dst, src, len, buf, blksize); ++ if (do_kfree) { ++ AuDebugOn(!au_kfree_do_sz_test(blksize)); ++ au_kfree_do_rcu(buf); ++ } else ++ free_page((unsigned long)buf); ++ ++out: ++ return err; ++} ++ ++static int au_do_copy(struct file *dst, struct file *src, loff_t len) ++{ ++ int err; ++ struct super_block *h_src_sb; ++ struct inode *h_src_inode; ++ ++ h_src_inode = file_inode(src); ++ h_src_sb = h_src_inode->i_sb; ++ ++ /* XFS acquires inode_lock */ ++ if (!au_test_xfs(h_src_sb)) ++ err = au_copy_file(dst, src, len); ++ else { ++ inode_unlock_shared(h_src_inode); ++ err = au_copy_file(dst, src, len); ++ inode_lock_shared_nested(h_src_inode, AuLsc_I_CHILD); ++ } ++ ++ return err; ++} ++ ++static int au_clone_or_copy(struct file *dst, struct file *src, loff_t len) ++{ ++ int err; ++ loff_t lo; ++ struct super_block *h_src_sb; ++ struct inode *h_src_inode; ++ ++ h_src_inode = file_inode(src); ++ h_src_sb = h_src_inode->i_sb; ++ if (h_src_sb != file_inode(dst)->i_sb ++ || !dst->f_op->remap_file_range) { ++ err = au_do_copy(dst, src, len); ++ goto out; ++ } ++ ++ if (!au_test_nfs(h_src_sb)) { ++ inode_unlock_shared(h_src_inode); ++ lo = vfsub_clone_file_range(src, dst, len); ++ inode_lock_shared_nested(h_src_inode, AuLsc_I_CHILD); ++ } else ++ lo = vfsub_clone_file_range(src, dst, len); ++ if (lo == len) { ++ err = 0; ++ goto out; /* success */ ++ } else if (lo >= 0) ++ /* todo: possible? */ ++ /* paritially succeeded */ ++ AuDbg("lo %lld, len %lld. Retrying.\n", lo, len); ++ else if (lo != -EOPNOTSUPP) { ++ /* older XFS has a condition in cloning */ ++ err = lo; ++ goto out; ++ } ++ ++ /* the backend fs on NFS may not support cloning */ ++ err = au_do_copy(dst, src, len); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * to support a sparse file which is opened with O_APPEND, ++ * we need to close the file. ++ */ ++static int au_cp_regular(struct au_cp_generic *cpg) ++{ ++ int err, i; ++ enum { SRC, DST }; ++ struct { ++ aufs_bindex_t bindex; ++ unsigned int flags; ++ struct dentry *dentry; ++ int force_wr; ++ struct file *file; ++ } *f, file[] = { ++ { ++ .bindex = cpg->bsrc, ++ .flags = O_RDONLY | O_NOATIME | O_LARGEFILE, ++ }, ++ { ++ .bindex = cpg->bdst, ++ .flags = O_WRONLY | O_NOATIME | O_LARGEFILE, ++ .force_wr = !!au_ftest_cpup(cpg->flags, RWDST), ++ } ++ }; ++ struct au_branch *br; ++ struct super_block *sb, *h_src_sb; ++ struct inode *h_src_inode; ++ struct task_struct *tsk = current; ++ ++ /* bsrc branch can be ro/rw. */ ++ sb = cpg->dentry->d_sb; ++ f = file; ++ for (i = 0; i < 2; i++, f++) { ++ f->dentry = au_h_dptr(cpg->dentry, f->bindex); ++ f->file = au_h_open(cpg->dentry, f->bindex, f->flags, ++ /*file*/NULL, f->force_wr); ++ if (IS_ERR(f->file)) { ++ err = PTR_ERR(f->file); ++ if (i == SRC) ++ goto out; ++ else ++ goto out_src; ++ } ++ } ++ ++ /* try stopping to update while we copyup */ ++ h_src_inode = d_inode(file[SRC].dentry); ++ h_src_sb = h_src_inode->i_sb; ++ if (!au_test_nfs(h_src_sb)) ++ IMustLock(h_src_inode); ++ err = au_clone_or_copy(file[DST].file, file[SRC].file, cpg->len); ++ ++ /* i wonder if we had O_NO_DELAY_FPUT flag */ ++ if (tsk->flags & PF_KTHREAD) ++ __fput_sync(file[DST].file); ++ else { ++ /* it happened actually */ ++ fput(file[DST].file); ++ /* ++ * too bad. ++ * we have to call both since we don't know which place the file ++ * was added to. ++ */ ++ task_work_run(); ++ flush_delayed_fput(); ++ } ++ br = au_sbr(sb, file[DST].bindex); ++ au_lcnt_dec(&br->br_nfiles); ++ ++out_src: ++ fput(file[SRC].file); ++ br = au_sbr(sb, file[SRC].bindex); ++ au_lcnt_dec(&br->br_nfiles); ++out: ++ return err; ++} ++ ++static int au_do_cpup_regular(struct au_cp_generic *cpg, ++ struct au_cpup_reg_attr *h_src_attr) ++{ ++ int err, rerr; ++ loff_t l; ++ struct path h_path; ++ struct inode *h_src_inode, *h_dst_inode; ++ ++ err = 0; ++ h_src_inode = au_h_iptr(d_inode(cpg->dentry), cpg->bsrc); ++ l = i_size_read(h_src_inode); ++ if (cpg->len == -1 || l < cpg->len) ++ cpg->len = l; ++ if (cpg->len) { ++ /* try stopping to update while we are referencing */ ++ inode_lock_shared_nested(h_src_inode, AuLsc_I_CHILD); ++ au_pin_hdir_unlock(cpg->pin); ++ ++ h_path.dentry = au_h_dptr(cpg->dentry, cpg->bsrc); ++ h_path.mnt = au_sbr_mnt(cpg->dentry->d_sb, cpg->bsrc); ++ h_src_attr->iflags = h_src_inode->i_flags; ++ if (!au_test_nfs(h_src_inode->i_sb)) ++ err = vfsub_getattr(&h_path, &h_src_attr->st); ++ else { ++ inode_unlock_shared(h_src_inode); ++ err = vfsub_getattr(&h_path, &h_src_attr->st); ++ inode_lock_shared_nested(h_src_inode, AuLsc_I_CHILD); ++ } ++ if (unlikely(err)) { ++ inode_unlock_shared(h_src_inode); ++ goto out; ++ } ++ h_src_attr->valid = 1; ++ if (!au_test_nfs(h_src_inode->i_sb)) { ++ err = au_cp_regular(cpg); ++ inode_unlock_shared(h_src_inode); ++ } else { ++ inode_unlock_shared(h_src_inode); ++ err = au_cp_regular(cpg); ++ } ++ rerr = au_pin_hdir_relock(cpg->pin); ++ if (!err && rerr) ++ err = rerr; ++ } ++ if (!err && (h_src_inode->i_state & I_LINKABLE)) { ++ h_path.dentry = au_h_dptr(cpg->dentry, cpg->bdst); ++ h_dst_inode = d_inode(h_path.dentry); ++ spin_lock(&h_dst_inode->i_lock); ++ h_dst_inode->i_state |= I_LINKABLE; ++ spin_unlock(&h_dst_inode->i_lock); ++ } ++ ++out: ++ return err; ++} ++ ++static int au_do_cpup_symlink(struct path *h_path, struct dentry *h_src, ++ struct inode *h_dir) ++{ ++ int err; ++ DEFINE_DELAYED_CALL(done); ++ const char *sym; ++ ++ sym = vfs_get_link(h_src, &done); ++ err = PTR_ERR(sym); ++ if (IS_ERR(sym)) ++ goto out; ++ ++ err = vfsub_symlink(h_dir, h_path, sym); ++ ++out: ++ do_delayed_call(&done); ++ return err; ++} ++ ++/* ++ * regardless 'acl' option, reset all ACL. ++ * All ACL will be copied up later from the original entry on the lower branch. ++ */ ++static int au_reset_acl(struct inode *h_dir, struct path *h_path, umode_t mode) ++{ ++ int err; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct user_namespace *h_userns; ++ ++ h_userns = mnt_user_ns(h_path->mnt); ++ h_dentry = h_path->dentry; ++ h_inode = d_inode(h_dentry); ++ /* forget_all_cached_acls(h_inode)); */ ++ err = vfsub_removexattr(h_userns, h_dentry, XATTR_NAME_POSIX_ACL_ACCESS); ++ AuTraceErr(err); ++ if (err == -EOPNOTSUPP) ++ err = 0; ++ if (!err) ++ err = vfsub_acl_chmod(h_userns, h_inode, mode); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_do_cpup_dir(struct au_cp_generic *cpg, struct dentry *dst_parent, ++ struct inode *h_dir, struct path *h_path) ++{ ++ int err; ++ struct inode *dir, *inode; ++ struct user_namespace *h_userns; ++ ++ h_userns = mnt_user_ns(h_path->mnt); ++ err = vfsub_removexattr(h_userns, h_path->dentry, ++ XATTR_NAME_POSIX_ACL_DEFAULT); ++ AuTraceErr(err); ++ if (err == -EOPNOTSUPP) ++ err = 0; ++ if (unlikely(err)) ++ goto out; ++ ++ /* ++ * strange behaviour from the users view, ++ * particularly setattr case ++ */ ++ dir = d_inode(dst_parent); ++ if (au_ibtop(dir) == cpg->bdst) ++ au_cpup_attr_nlink(dir, /*force*/1); ++ inode = d_inode(cpg->dentry); ++ au_cpup_attr_nlink(inode, /*force*/1); ++ ++out: ++ return err; ++} ++ ++static noinline_for_stack ++int cpup_entry(struct au_cp_generic *cpg, struct dentry *dst_parent, ++ struct au_cpup_reg_attr *h_src_attr) ++{ ++ int err; ++ umode_t mode; ++ unsigned int mnt_flags; ++ unsigned char isdir, isreg, force; ++ const unsigned char do_dt = !!au_ftest_cpup(cpg->flags, DTIME); ++ struct au_dtime dt; ++ struct path h_path; ++ struct dentry *h_src, *h_dst, *h_parent; ++ struct inode *h_inode, *h_dir; ++ struct super_block *sb; ++ ++ /* bsrc branch can be ro/rw. */ ++ h_src = au_h_dptr(cpg->dentry, cpg->bsrc); ++ h_inode = d_inode(h_src); ++ AuDebugOn(h_inode != au_h_iptr(d_inode(cpg->dentry), cpg->bsrc)); ++ ++ /* try stopping to be referenced while we are creating */ ++ h_dst = au_h_dptr(cpg->dentry, cpg->bdst); ++ if (au_ftest_cpup(cpg->flags, RENAME)) ++ AuDebugOn(strncmp(h_dst->d_name.name, AUFS_WH_PFX, ++ AUFS_WH_PFX_LEN)); ++ h_parent = h_dst->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ AuDebugOn(h_parent != h_dst->d_parent); ++ ++ sb = cpg->dentry->d_sb; ++ h_path.mnt = au_sbr_mnt(sb, cpg->bdst); ++ if (do_dt) { ++ h_path.dentry = h_parent; ++ au_dtime_store(&dt, dst_parent, &h_path); ++ } ++ h_path.dentry = h_dst; ++ ++ isreg = 0; ++ isdir = 0; ++ mode = h_inode->i_mode; ++ switch (mode & S_IFMT) { ++ case S_IFREG: ++ isreg = 1; ++ err = vfsub_create(h_dir, &h_path, 0600, /*want_excl*/true); ++ if (!err) ++ err = au_do_cpup_regular(cpg, h_src_attr); ++ break; ++ case S_IFDIR: ++ isdir = 1; ++ err = vfsub_mkdir(h_dir, &h_path, mode); ++ if (!err) ++ err = au_do_cpup_dir(cpg, dst_parent, h_dir, &h_path); ++ break; ++ case S_IFLNK: ++ err = au_do_cpup_symlink(&h_path, h_src, h_dir); ++ break; ++ case S_IFCHR: ++ case S_IFBLK: ++ AuDebugOn(!capable(CAP_MKNOD)); ++ fallthrough; ++ case S_IFIFO: ++ case S_IFSOCK: ++ err = vfsub_mknod(h_dir, &h_path, mode, h_inode->i_rdev); ++ break; ++ default: ++ AuIOErr("Unknown inode type 0%o\n", mode); ++ err = -EIO; ++ } ++ if (!err) ++ err = au_reset_acl(h_dir, &h_path, mode); ++ ++ mnt_flags = au_mntflags(sb); ++ if (!au_opt_test(mnt_flags, UDBA_NONE) ++ && !isdir ++ && au_opt_test(mnt_flags, XINO) ++ && (h_inode->i_nlink == 1 ++ || (h_inode->i_state & I_LINKABLE)) ++ /* todo: unnecessary? */ ++ /* && d_inode(cpg->dentry)->i_nlink == 1 */ ++ && cpg->bdst < cpg->bsrc ++ && !au_ftest_cpup(cpg->flags, KEEPLINO)) ++ au_xino_write(sb, cpg->bsrc, h_inode->i_ino, /*ino*/0); ++ /* ignore this error */ ++ ++ if (!err) { ++ force = 0; ++ if (isreg) { ++ force = !!cpg->len; ++ if (cpg->len == -1) ++ force = !!i_size_read(h_inode); ++ } ++ au_fhsm_wrote(sb, cpg->bdst, force); ++ } ++ ++ if (do_dt) ++ au_dtime_revert(&dt); ++ return err; ++} ++ ++static int au_do_ren_after_cpup(struct au_cp_generic *cpg, struct path *h_path) ++{ ++ int err; ++ struct dentry *dentry, *h_dentry, *h_parent, *parent; ++ struct path h_ppath; ++ struct inode *h_dir; ++ aufs_bindex_t bdst; ++ ++ dentry = cpg->dentry; ++ bdst = cpg->bdst; ++ h_ppath.mnt = au_sbr_mnt(dentry->d_sb, bdst); ++ h_dentry = au_h_dptr(dentry, bdst); ++ if (!au_ftest_cpup(cpg->flags, OVERWRITE)) { ++ dget(h_dentry); ++ au_set_h_dptr(dentry, bdst, NULL); ++ err = au_lkup_neg(dentry, bdst, /*wh*/0); ++ if (!err) ++ h_path->dentry = dget(au_h_dptr(dentry, bdst)); ++ au_set_h_dptr(dentry, bdst, h_dentry); ++ } else { ++ err = 0; ++ parent = dget_parent(dentry); ++ h_ppath.dentry = au_h_dptr(parent, bdst); ++ dput(parent); ++ h_path->dentry = vfsub_lkup_one(&dentry->d_name, &h_ppath); ++ if (IS_ERR(h_path->dentry)) ++ err = PTR_ERR(h_path->dentry); ++ } ++ if (unlikely(err)) ++ goto out; ++ ++ h_parent = h_dentry->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ AuDbg("%pd %pd\n", h_dentry, h_path->dentry); ++ /* no delegation since it is just created */ ++ err = vfsub_rename(h_dir, h_dentry, h_dir, h_path, /*delegated*/NULL, ++ /*flags*/0); ++ dput(h_path->dentry); ++ ++out: ++ return err; ++} ++ ++/* ++ * copyup the @dentry from @bsrc to @bdst. ++ * the caller must set the both of lower dentries. ++ * @len is for truncating when it is -1 copyup the entire file. ++ * in link/rename cases, @dst_parent may be different from the real one. ++ * basic->bsrc can be larger than basic->bdst. ++ * aufs doesn't touch the credential so ++ * security_inode_copy_up{,_xattr}() are unnecessary. ++ */ ++static int au_cpup_single(struct au_cp_generic *cpg, struct dentry *dst_parent) ++{ ++ int err, rerr; ++ aufs_bindex_t old_ibtop; ++ unsigned char isdir, plink; ++ struct dentry *h_src, *h_dst, *h_parent; ++ struct inode *dst_inode, *h_dir, *inode, *delegated, *src_inode; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct path h_src_path; ++ /* to reduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct path h_path; ++ struct au_cpup_reg_attr h_src_attr; ++ } *a; ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ a->h_src_attr.valid = 0; ++ ++ sb = cpg->dentry->d_sb; ++ br = au_sbr(sb, cpg->bdst); ++ a->h_path.mnt = au_br_mnt(br); ++ h_dst = au_h_dptr(cpg->dentry, cpg->bdst); ++ h_parent = h_dst->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ ++ h_src = au_h_dptr(cpg->dentry, cpg->bsrc); ++ inode = d_inode(cpg->dentry); ++ ++ if (!dst_parent) ++ dst_parent = dget_parent(cpg->dentry); ++ else ++ dget(dst_parent); ++ ++ plink = !!au_opt_test(au_mntflags(sb), PLINK); ++ dst_inode = au_h_iptr(inode, cpg->bdst); ++ if (dst_inode) { ++ if (unlikely(!plink)) { ++ err = -EIO; ++ AuIOErr("hi%lu(i%lu) exists on b%d " ++ "but plink is disabled\n", ++ dst_inode->i_ino, inode->i_ino, cpg->bdst); ++ goto out_parent; ++ } ++ ++ if (dst_inode->i_nlink) { ++ const int do_dt = au_ftest_cpup(cpg->flags, DTIME); ++ ++ h_src = au_plink_lkup(inode, cpg->bdst); ++ err = PTR_ERR(h_src); ++ if (IS_ERR(h_src)) ++ goto out_parent; ++ if (unlikely(d_is_negative(h_src))) { ++ err = -EIO; ++ AuIOErr("i%lu exists on b%d " ++ "but not pseudo-linked\n", ++ inode->i_ino, cpg->bdst); ++ dput(h_src); ++ goto out_parent; ++ } ++ ++ if (do_dt) { ++ a->h_path.dentry = h_parent; ++ au_dtime_store(&a->dt, dst_parent, &a->h_path); ++ } ++ ++ a->h_path.dentry = h_dst; ++ delegated = NULL; ++ err = vfsub_link(h_src, h_dir, &a->h_path, &delegated); ++ if (!err && au_ftest_cpup(cpg->flags, RENAME)) ++ err = au_do_ren_after_cpup(cpg, &a->h_path); ++ if (do_dt) ++ au_dtime_revert(&a->dt); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ dput(h_src); ++ goto out_parent; ++ } else ++ /* todo: cpup_wh_file? */ ++ /* udba work */ ++ au_update_ibrange(inode, /*do_put_zero*/1); ++ } ++ ++ isdir = S_ISDIR(inode->i_mode); ++ old_ibtop = au_ibtop(inode); ++ err = cpup_entry(cpg, dst_parent, &a->h_src_attr); ++ if (unlikely(err)) ++ goto out_rev; ++ dst_inode = d_inode(h_dst); ++ inode_lock_nested(dst_inode, AuLsc_I_CHILD2); ++ /* todo: necessary? */ ++ /* au_pin_hdir_unlock(cpg->pin); */ ++ ++ h_src_path.dentry = h_src; ++ h_src_path.mnt = au_sbr_mnt(sb, cpg->bsrc); ++ err = cpup_iattr(cpg->dentry, cpg->bdst, &h_src_path, &a->h_src_attr); ++ if (unlikely(err)) { ++ /* todo: necessary? */ ++ /* au_pin_hdir_relock(cpg->pin); */ /* ignore an error */ ++ inode_unlock(dst_inode); ++ goto out_rev; ++ } ++ ++ if (cpg->bdst < old_ibtop) { ++ if (S_ISREG(inode->i_mode)) { ++ err = au_dy_iaop(inode, cpg->bdst, dst_inode); ++ if (unlikely(err)) { ++ /* ignore an error */ ++ /* au_pin_hdir_relock(cpg->pin); */ ++ inode_unlock(dst_inode); ++ goto out_rev; ++ } ++ } ++ au_set_ibtop(inode, cpg->bdst); ++ } else ++ au_set_ibbot(inode, cpg->bdst); ++ au_set_h_iptr(inode, cpg->bdst, au_igrab(dst_inode), ++ au_hi_flags(inode, isdir)); ++ ++ /* todo: necessary? */ ++ /* err = au_pin_hdir_relock(cpg->pin); */ ++ inode_unlock(dst_inode); ++ if (unlikely(err)) ++ goto out_rev; ++ ++ src_inode = d_inode(h_src); ++ if (!isdir ++ && (src_inode->i_nlink > 1 ++ || src_inode->i_state & I_LINKABLE) ++ && plink) ++ au_plink_append(inode, cpg->bdst, h_dst); ++ ++ if (au_ftest_cpup(cpg->flags, RENAME)) { ++ a->h_path.dentry = h_dst; ++ err = au_do_ren_after_cpup(cpg, &a->h_path); ++ } ++ if (!err) ++ goto out_parent; /* success */ ++ ++ /* revert */ ++out_rev: ++ a->h_path.dentry = h_parent; ++ au_dtime_store(&a->dt, dst_parent, &a->h_path); ++ a->h_path.dentry = h_dst; ++ rerr = 0; ++ if (d_is_positive(h_dst)) { ++ if (!isdir) { ++ /* no delegation since it is just created */ ++ rerr = vfsub_unlink(h_dir, &a->h_path, ++ /*delegated*/NULL, /*force*/0); ++ } else ++ rerr = vfsub_rmdir(h_dir, &a->h_path); ++ } ++ au_dtime_revert(&a->dt); ++ if (rerr) { ++ AuIOErr("failed removing broken entry(%d, %d)\n", err, rerr); ++ err = -EIO; ++ } ++out_parent: ++ dput(dst_parent); ++ au_kfree_rcu(a); ++out: ++ return err; ++} ++ ++#if 0 /* reserved */ ++struct au_cpup_single_args { ++ int *errp; ++ struct au_cp_generic *cpg; ++ struct dentry *dst_parent; ++}; ++ ++static void au_call_cpup_single(void *args) ++{ ++ struct au_cpup_single_args *a = args; ++ ++ au_pin_hdir_acquire_nest(a->cpg->pin); ++ *a->errp = au_cpup_single(a->cpg, a->dst_parent); ++ au_pin_hdir_release(a->cpg->pin); ++} ++#endif ++ ++/* ++ * prevent SIGXFSZ in copy-up. ++ * testing CAP_MKNOD is for generic fs, ++ * but CAP_FSETID is for xfs only, currently. ++ */ ++static int au_cpup_sio_test(struct au_pin *pin, umode_t mode) ++{ ++ int do_sio; ++ struct super_block *sb; ++ struct inode *h_dir; ++ ++ do_sio = 0; ++ sb = au_pinned_parent(pin)->d_sb; ++ if (!au_wkq_test() ++ && (!au_sbi(sb)->si_plink_maint_pid ++ || au_plink_maint(sb, AuLock_NOPLM))) { ++ switch (mode & S_IFMT) { ++ case S_IFREG: ++ /* no condition about RLIMIT_FSIZE and the file size */ ++ do_sio = 1; ++ break; ++ case S_IFCHR: ++ case S_IFBLK: ++ do_sio = !capable(CAP_MKNOD); ++ break; ++ } ++ if (!do_sio) ++ do_sio = ((mode & (S_ISUID | S_ISGID)) ++ && !capable(CAP_FSETID)); ++ /* this workaround may be removed in the future */ ++ if (!do_sio) { ++ h_dir = au_pinned_h_dir(pin); ++ do_sio = h_dir->i_mode & S_ISVTX; ++ } ++ } ++ ++ return do_sio; ++} ++ ++#if 0 /* reserved */ ++int au_sio_cpup_single(struct au_cp_generic *cpg, struct dentry *dst_parent) ++{ ++ int err, wkq_err; ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(cpg->dentry, cpg->bsrc); ++ if (!au_cpup_sio_test(pin, d_inode(h_dentry)->i_mode)) ++ err = au_cpup_single(cpg, dst_parent); ++ else { ++ struct au_cpup_single_args args = { ++ .errp = &err, ++ .cpg = cpg, ++ .dst_parent = dst_parent ++ }; ++ wkq_err = au_wkq_wait(au_call_cpup_single, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ return err; ++} ++#endif ++ ++/* ++ * copyup the @dentry from the first active lower branch to @bdst, ++ * using au_cpup_single(). ++ */ ++static int au_cpup_simple(struct au_cp_generic *cpg) ++{ ++ int err; ++ unsigned int flags_orig; ++ struct dentry *dentry; ++ ++ AuDebugOn(cpg->bsrc < 0); ++ ++ dentry = cpg->dentry; ++ DiMustWriteLock(dentry); ++ ++ err = au_lkup_neg(dentry, cpg->bdst, /*wh*/1); ++ if (!err) { ++ flags_orig = cpg->flags; ++ au_fset_cpup(cpg->flags, RENAME); ++ err = au_cpup_single(cpg, NULL); ++ cpg->flags = flags_orig; ++ if (!err) ++ return 0; /* success */ ++ ++ /* revert */ ++ au_set_h_dptr(dentry, cpg->bdst, NULL); ++ au_set_dbtop(dentry, cpg->bsrc); ++ } ++ ++ return err; ++} ++ ++struct au_cpup_simple_args { ++ int *errp; ++ struct au_cp_generic *cpg; ++}; ++ ++static void au_call_cpup_simple(void *args) ++{ ++ struct au_cpup_simple_args *a = args; ++ ++ au_pin_hdir_acquire_nest(a->cpg->pin); ++ *a->errp = au_cpup_simple(a->cpg); ++ au_pin_hdir_release(a->cpg->pin); ++} ++ ++static int au_do_sio_cpup_simple(struct au_cp_generic *cpg) ++{ ++ int err, wkq_err; ++ struct dentry *dentry, *parent; ++ struct file *h_file; ++ struct inode *h_dir; ++ struct user_namespace *h_userns; ++ ++ dentry = cpg->dentry; ++ h_file = NULL; ++ if (au_ftest_cpup(cpg->flags, HOPEN)) { ++ AuDebugOn(cpg->bsrc < 0); ++ h_file = au_h_open_pre(dentry, cpg->bsrc, /*force_wr*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ } ++ ++ parent = dget_parent(dentry); ++ h_dir = au_h_iptr(d_inode(parent), cpg->bdst); ++ h_userns = au_sbr_userns(dentry->d_sb, cpg->bdst); ++ if (!au_test_h_perm_sio(h_userns, h_dir, MAY_EXEC | MAY_WRITE) ++ && !au_cpup_sio_test(cpg->pin, d_inode(dentry)->i_mode)) ++ err = au_cpup_simple(cpg); ++ else { ++ struct au_cpup_simple_args args = { ++ .errp = &err, ++ .cpg = cpg ++ }; ++ wkq_err = au_wkq_wait(au_call_cpup_simple, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ dput(parent); ++ if (h_file) ++ au_h_open_post(dentry, cpg->bsrc, h_file); ++ ++out: ++ return err; ++} ++ ++int au_sio_cpup_simple(struct au_cp_generic *cpg) ++{ ++ aufs_bindex_t bsrc, bbot; ++ struct dentry *dentry, *h_dentry; ++ ++ if (cpg->bsrc < 0) { ++ dentry = cpg->dentry; ++ bbot = au_dbbot(dentry); ++ for (bsrc = cpg->bdst + 1; bsrc <= bbot; bsrc++) { ++ h_dentry = au_h_dptr(dentry, bsrc); ++ if (h_dentry) { ++ AuDebugOn(d_is_negative(h_dentry)); ++ break; ++ } ++ } ++ AuDebugOn(bsrc > bbot); ++ cpg->bsrc = bsrc; ++ } ++ AuDebugOn(cpg->bsrc <= cpg->bdst); ++ return au_do_sio_cpup_simple(cpg); ++} ++ ++int au_sio_cpdown_simple(struct au_cp_generic *cpg) ++{ ++ AuDebugOn(cpg->bdst <= cpg->bsrc); ++ return au_do_sio_cpup_simple(cpg); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * copyup the deleted file for writing. ++ */ ++static int au_do_cpup_wh(struct au_cp_generic *cpg, struct dentry *wh_dentry, ++ struct file *file) ++{ ++ int err; ++ unsigned int flags_orig; ++ aufs_bindex_t bsrc_orig; ++ struct au_dinfo *dinfo; ++ struct { ++ struct au_hdentry *hd; ++ struct dentry *h_dentry; ++ } hdst, hsrc; ++ ++ dinfo = au_di(cpg->dentry); ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ bsrc_orig = cpg->bsrc; ++ cpg->bsrc = dinfo->di_btop; ++ hdst.hd = au_hdentry(dinfo, cpg->bdst); ++ hdst.h_dentry = hdst.hd->hd_dentry; ++ hdst.hd->hd_dentry = wh_dentry; ++ dinfo->di_btop = cpg->bdst; ++ ++ hsrc.h_dentry = NULL; ++ if (file) { ++ hsrc.hd = au_hdentry(dinfo, cpg->bsrc); ++ hsrc.h_dentry = hsrc.hd->hd_dentry; ++ hsrc.hd->hd_dentry = au_hf_top(file)->f_path.dentry; ++ } ++ flags_orig = cpg->flags; ++ cpg->flags = !AuCpup_DTIME; ++ err = au_cpup_single(cpg, /*h_parent*/NULL); ++ cpg->flags = flags_orig; ++ if (file) { ++ if (!err) ++ err = au_reopen_nondir(file); ++ hsrc.hd->hd_dentry = hsrc.h_dentry; ++ } ++ hdst.hd->hd_dentry = hdst.h_dentry; ++ dinfo->di_btop = cpg->bsrc; ++ cpg->bsrc = bsrc_orig; ++ ++ return err; ++} ++ ++static int au_cpup_wh(struct au_cp_generic *cpg, struct file *file) ++{ ++ int err; ++ aufs_bindex_t bdst; ++ struct au_dtime dt; ++ struct dentry *dentry, *parent, *h_parent, *wh_dentry; ++ struct au_branch *br; ++ struct path h_path; ++ ++ dentry = cpg->dentry; ++ bdst = cpg->bdst; ++ br = au_sbr(dentry->d_sb, bdst); ++ parent = dget_parent(dentry); ++ h_parent = au_h_dptr(parent, bdst); ++ wh_dentry = au_whtmp_lkup(h_parent, br, &dentry->d_name); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out; ++ ++ h_path.dentry = h_parent; ++ h_path.mnt = au_br_mnt(br); ++ au_dtime_store(&dt, parent, &h_path); ++ err = au_do_cpup_wh(cpg, wh_dentry, file); ++ if (unlikely(err)) ++ goto out_wh; ++ ++ dget(wh_dentry); ++ h_path.dentry = wh_dentry; ++ if (!d_is_dir(wh_dentry)) { ++ /* no delegation since it is just created */ ++ err = vfsub_unlink(d_inode(h_parent), &h_path, ++ /*delegated*/NULL, /*force*/0); ++ } else ++ err = vfsub_rmdir(d_inode(h_parent), &h_path); ++ if (unlikely(err)) { ++ AuIOErr("failed remove copied-up tmp file %pd(%d)\n", ++ wh_dentry, err); ++ err = -EIO; ++ } ++ au_dtime_revert(&dt); ++ au_set_hi_wh(d_inode(dentry), bdst, wh_dentry); ++ ++out_wh: ++ dput(wh_dentry); ++out: ++ dput(parent); ++ return err; ++} ++ ++struct au_cpup_wh_args { ++ int *errp; ++ struct au_cp_generic *cpg; ++ struct file *file; ++}; ++ ++static void au_call_cpup_wh(void *args) ++{ ++ struct au_cpup_wh_args *a = args; ++ ++ au_pin_hdir_acquire_nest(a->cpg->pin); ++ *a->errp = au_cpup_wh(a->cpg, a->file); ++ au_pin_hdir_release(a->cpg->pin); ++} ++ ++int au_sio_cpup_wh(struct au_cp_generic *cpg, struct file *file) ++{ ++ int err, wkq_err; ++ aufs_bindex_t bdst; ++ struct dentry *dentry, *parent, *h_orph, *h_parent; ++ struct inode *dir, *h_dir, *h_tmpdir; ++ struct au_wbr *wbr; ++ struct au_pin wh_pin, *pin_orig; ++ struct user_namespace *h_userns; ++ ++ dentry = cpg->dentry; ++ bdst = cpg->bdst; ++ parent = dget_parent(dentry); ++ dir = d_inode(parent); ++ h_orph = NULL; ++ h_parent = NULL; ++ h_dir = au_igrab(au_h_iptr(dir, bdst)); ++ h_tmpdir = h_dir; ++ pin_orig = NULL; ++ if (!h_dir->i_nlink) { ++ wbr = au_sbr(dentry->d_sb, bdst)->br_wbr; ++ h_orph = wbr->wbr_orph; ++ ++ h_parent = dget(au_h_dptr(parent, bdst)); ++ au_set_h_dptr(parent, bdst, dget(h_orph)); ++ h_tmpdir = d_inode(h_orph); ++ au_set_h_iptr(dir, bdst, au_igrab(h_tmpdir), /*flags*/0); ++ ++ inode_lock_nested(h_tmpdir, AuLsc_I_PARENT3); ++ /* todo: au_h_open_pre()? */ ++ ++ pin_orig = cpg->pin; ++ au_pin_init(&wh_pin, dentry, bdst, AuLsc_DI_PARENT, ++ AuLsc_I_PARENT3, cpg->pin->udba, AuPin_DI_LOCKED); ++ cpg->pin = &wh_pin; ++ } ++ ++ h_userns = au_sbr_userns(dentry->d_sb, bdst); ++ if (!au_test_h_perm_sio(h_userns, h_tmpdir, MAY_EXEC | MAY_WRITE) ++ && !au_cpup_sio_test(cpg->pin, d_inode(dentry)->i_mode)) ++ err = au_cpup_wh(cpg, file); ++ else { ++ struct au_cpup_wh_args args = { ++ .errp = &err, ++ .cpg = cpg, ++ .file = file ++ }; ++ wkq_err = au_wkq_wait(au_call_cpup_wh, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ if (h_orph) { ++ inode_unlock(h_tmpdir); ++ /* todo: au_h_open_post()? */ ++ au_set_h_iptr(dir, bdst, au_igrab(h_dir), /*flags*/0); ++ au_set_h_dptr(parent, bdst, h_parent); ++ AuDebugOn(!pin_orig); ++ cpg->pin = pin_orig; ++ } ++ iput(h_dir); ++ dput(parent); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * generic routine for both of copy-up and copy-down. ++ */ ++/* cf. revalidate function in file.c */ ++int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst, ++ int (*cp)(struct dentry *dentry, aufs_bindex_t bdst, ++ struct au_pin *pin, ++ struct dentry *h_parent, void *arg), ++ void *arg) ++{ ++ int err; ++ struct au_pin pin; ++ struct dentry *d, *parent, *h_parent, *real_parent, *h_dentry; ++ ++ err = 0; ++ parent = dget_parent(dentry); ++ if (IS_ROOT(parent)) ++ goto out; ++ ++ au_pin_init(&pin, dentry, bdst, AuLsc_DI_PARENT2, AuLsc_I_PARENT2, ++ au_opt_udba(dentry->d_sb), AuPin_MNT_WRITE); ++ ++ /* do not use au_dpage */ ++ real_parent = parent; ++ while (1) { ++ dput(parent); ++ parent = dget_parent(dentry); ++ h_parent = au_h_dptr(parent, bdst); ++ if (h_parent) ++ goto out; /* success */ ++ ++ /* find top dir which is necessary to cpup */ ++ do { ++ d = parent; ++ dput(parent); ++ parent = dget_parent(d); ++ di_read_lock_parent3(parent, !AuLock_IR); ++ h_parent = au_h_dptr(parent, bdst); ++ di_read_unlock(parent, !AuLock_IR); ++ } while (!h_parent); ++ ++ if (d != real_parent) ++ di_write_lock_child3(d); ++ ++ /* somebody else might create while we were sleeping */ ++ h_dentry = au_h_dptr(d, bdst); ++ if (!h_dentry || d_is_negative(h_dentry)) { ++ if (h_dentry) ++ au_update_dbtop(d); ++ ++ au_pin_set_dentry(&pin, d); ++ err = au_do_pin(&pin); ++ if (!err) { ++ err = cp(d, bdst, &pin, h_parent, arg); ++ au_unpin(&pin); ++ } ++ } ++ ++ if (d != real_parent) ++ di_write_unlock(d); ++ if (unlikely(err)) ++ break; ++ } ++ ++out: ++ dput(parent); ++ return err; ++} ++ ++static int au_cpup_dir(struct dentry *dentry, aufs_bindex_t bdst, ++ struct au_pin *pin, ++ struct dentry *h_parent __maybe_unused, ++ void *arg __maybe_unused) ++{ ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = bdst, ++ .bsrc = -1, ++ .len = 0, ++ .pin = pin, ++ .flags = AuCpup_DTIME ++ }; ++ return au_sio_cpup_simple(&cpg); ++} ++ ++int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst) ++{ ++ return au_cp_dirs(dentry, bdst, au_cpup_dir, NULL); ++} ++ ++int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst) ++{ ++ int err; ++ struct dentry *parent; ++ struct inode *dir; ++ ++ parent = dget_parent(dentry); ++ dir = d_inode(parent); ++ err = 0; ++ if (au_h_iptr(dir, bdst)) ++ goto out; ++ ++ di_read_unlock(parent, AuLock_IR); ++ di_write_lock_parent(parent); ++ /* someone else might change our inode while we were sleeping */ ++ if (!au_h_iptr(dir, bdst)) ++ err = au_cpup_dirs(dentry, bdst); ++ di_downgrade_lock(parent, AuLock_IR); ++ ++out: ++ dput(parent); ++ return err; ++} +diff -Naur null/fs/aufs/cpup.h linux-5.15.36/fs/aufs/cpup.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/cpup.h 2022-05-10 16:51:39.867744220 +0300 +@@ -0,0 +1,100 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * copy-up/down functions ++ */ ++ ++#ifndef __AUFS_CPUP_H__ ++#define __AUFS_CPUP_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++struct inode; ++struct file; ++struct au_pin; ++ ++void au_cpup_attr_flags(struct inode *dst, unsigned int iflags); ++void au_cpup_attr_timesizes(struct inode *inode); ++void au_cpup_attr_nlink(struct inode *inode, int force); ++void au_cpup_attr_changeable(struct inode *inode); ++void au_cpup_igen(struct inode *inode, struct inode *h_inode); ++void au_cpup_attr_all(struct inode *inode, int force); ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_cp_generic { ++ struct dentry *dentry; ++ aufs_bindex_t bdst, bsrc; ++ loff_t len; ++ struct au_pin *pin; ++ unsigned int flags; ++}; ++ ++/* cpup flags */ ++#define AuCpup_DTIME 1 /* do dtime_store/revert */ ++#define AuCpup_KEEPLINO (1 << 1) /* do not clear the lower xino, ++ for link(2) */ ++#define AuCpup_RENAME (1 << 2) /* rename after cpup */ ++#define AuCpup_HOPEN (1 << 3) /* call h_open_pre/post() in ++ cpup */ ++#define AuCpup_OVERWRITE (1 << 4) /* allow overwriting the ++ existing entry */ ++#define AuCpup_RWDST (1 << 5) /* force write target even if ++ the branch is marked as RO */ ++ ++#ifndef CONFIG_AUFS_BR_HFSPLUS ++#undef AuCpup_HOPEN ++#define AuCpup_HOPEN 0 ++#endif ++ ++#define au_ftest_cpup(flags, name) ((flags) & AuCpup_##name) ++#define au_fset_cpup(flags, name) \ ++ do { (flags) |= AuCpup_##name; } while (0) ++#define au_fclr_cpup(flags, name) \ ++ do { (flags) &= ~AuCpup_##name; } while (0) ++ ++int au_copy_file(struct file *dst, struct file *src, loff_t len); ++int au_sio_cpup_simple(struct au_cp_generic *cpg); ++int au_sio_cpdown_simple(struct au_cp_generic *cpg); ++int au_sio_cpup_wh(struct au_cp_generic *cpg, struct file *file); ++ ++int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst, ++ int (*cp)(struct dentry *dentry, aufs_bindex_t bdst, ++ struct au_pin *pin, ++ struct dentry *h_parent, void *arg), ++ void *arg); ++int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst); ++int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* keep timestamps when copyup */ ++struct au_dtime { ++ struct dentry *dt_dentry; ++ struct path dt_h_path; ++ struct timespec64 dt_atime, dt_mtime; ++}; ++void au_dtime_store(struct au_dtime *dt, struct dentry *dentry, ++ struct path *h_path); ++void au_dtime_revert(struct au_dtime *dt); ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_CPUP_H__ */ +diff -Naur null/fs/aufs/dbgaufs.c linux-5.15.36/fs/aufs/dbgaufs.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/dbgaufs.c 2022-05-10 16:51:39.867744220 +0300 +@@ -0,0 +1,526 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * debugfs interface ++ */ ++ ++#include ++#include "aufs.h" ++ ++#ifndef CONFIG_SYSFS ++#error DEBUG_FS depends upon SYSFS ++#endif ++ ++static struct dentry *dbgaufs; ++static const mode_t dbgaufs_mode = 0444; ++ ++/* 20 is max digits length of ulong 64 */ ++struct dbgaufs_arg { ++ int n; ++ char a[20 * 4]; ++}; ++ ++/* ++ * common function for all XINO files ++ */ ++static int dbgaufs_xi_release(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ void *p; ++ ++ p = file->private_data; ++ if (p) { ++ /* this is struct dbgaufs_arg */ ++ AuDebugOn(!au_kfree_sz_test(p)); ++ au_kfree_do_rcu(p); ++ } ++ return 0; ++} ++ ++static int dbgaufs_xi_open(struct file *xf, struct file *file, int do_fcnt, ++ int cnt) ++{ ++ int err; ++ struct kstat st; ++ struct dbgaufs_arg *p; ++ ++ err = -ENOMEM; ++ p = kmalloc(sizeof(*p), GFP_NOFS); ++ if (unlikely(!p)) ++ goto out; ++ ++ err = 0; ++ p->n = 0; ++ file->private_data = p; ++ if (!xf) ++ goto out; ++ ++ err = vfsub_getattr(&xf->f_path, &st); ++ if (!err) { ++ if (do_fcnt) ++ p->n = snprintf ++ (p->a, sizeof(p->a), "%d, %llux%u %lld\n", ++ cnt, st.blocks, st.blksize, ++ (long long)st.size); ++ else ++ p->n = snprintf(p->a, sizeof(p->a), "%llux%u %lld\n", ++ st.blocks, st.blksize, ++ (long long)st.size); ++ AuDebugOn(p->n >= sizeof(p->a)); ++ } else { ++ p->n = snprintf(p->a, sizeof(p->a), "err %d\n", err); ++ err = 0; ++ } ++ ++out: ++ return err; ++} ++ ++static ssize_t dbgaufs_xi_read(struct file *file, char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct dbgaufs_arg *p; ++ ++ p = file->private_data; ++ return simple_read_from_buffer(buf, count, ppos, p->a, p->n); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct dbgaufs_plink_arg { ++ int n; ++ char a[]; ++}; ++ ++static int dbgaufs_plink_release(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ free_page((unsigned long)file->private_data); ++ return 0; ++} ++ ++static int dbgaufs_plink_open(struct inode *inode, struct file *file) ++{ ++ int err, i, limit; ++ unsigned long n, sum; ++ struct dbgaufs_plink_arg *p; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ struct hlist_bl_head *hbl; ++ ++ err = -ENOMEM; ++ p = (void *)get_zeroed_page(GFP_NOFS); ++ if (unlikely(!p)) ++ goto out; ++ ++ err = -EFBIG; ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ if (au_opt_test(au_mntflags(sb), PLINK)) { ++ limit = PAGE_SIZE - sizeof(p->n); ++ ++ /* the number of buckets */ ++ n = snprintf(p->a + p->n, limit, "%d\n", AuPlink_NHASH); ++ p->n += n; ++ limit -= n; ++ ++ sum = 0; ++ for (i = 0, hbl = sbinfo->si_plink; i < AuPlink_NHASH; ++ i++, hbl++) { ++ n = au_hbl_count(hbl); ++ sum += n; ++ ++ n = snprintf(p->a + p->n, limit, "%lu ", n); ++ p->n += n; ++ limit -= n; ++ if (unlikely(limit <= 0)) ++ goto out_free; ++ } ++ p->a[p->n - 1] = '\n'; ++ ++ /* the sum of plinks */ ++ n = snprintf(p->a + p->n, limit, "%lu\n", sum); ++ p->n += n; ++ limit -= n; ++ if (unlikely(limit <= 0)) ++ goto out_free; ++ } else { ++#define str "1\n0\n0\n" ++ p->n = sizeof(str) - 1; ++ strcpy(p->a, str); ++#undef str ++ } ++ si_read_unlock(sb); ++ ++ err = 0; ++ file->private_data = p; ++ goto out; /* success */ ++ ++out_free: ++ free_page((unsigned long)p); ++out: ++ return err; ++} ++ ++static ssize_t dbgaufs_plink_read(struct file *file, char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct dbgaufs_plink_arg *p; ++ ++ p = file->private_data; ++ return simple_read_from_buffer(buf, count, ppos, p->a, p->n); ++} ++ ++static const struct file_operations dbgaufs_plink_fop = { ++ .owner = THIS_MODULE, ++ .open = dbgaufs_plink_open, ++ .release = dbgaufs_plink_release, ++ .read = dbgaufs_plink_read ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int dbgaufs_xib_open(struct inode *inode, struct file *file) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ err = dbgaufs_xi_open(sbinfo->si_xib, file, /*do_fcnt*/0, /*cnt*/0); ++ si_read_unlock(sb); ++ return err; ++} ++ ++static const struct file_operations dbgaufs_xib_fop = { ++ .owner = THIS_MODULE, ++ .open = dbgaufs_xib_open, ++ .release = dbgaufs_xi_release, ++ .read = dbgaufs_xi_read ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define DbgaufsXi_PREFIX "xi" ++ ++static int dbgaufs_xino_open(struct inode *inode, struct file *file) ++{ ++ int err, idx; ++ long l; ++ aufs_bindex_t bindex; ++ char *p, a[sizeof(DbgaufsXi_PREFIX) + 8]; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ struct au_xino *xi; ++ struct file *xf; ++ struct qstr *name; ++ struct au_branch *br; ++ ++ err = -ENOENT; ++ name = &file->f_path.dentry->d_name; ++ if (unlikely(name->len < sizeof(DbgaufsXi_PREFIX) ++ || memcmp(name->name, DbgaufsXi_PREFIX, ++ sizeof(DbgaufsXi_PREFIX) - 1))) ++ goto out; ++ ++ AuDebugOn(name->len >= sizeof(a)); ++ memcpy(a, name->name, name->len); ++ a[name->len] = '\0'; ++ p = strchr(a, '-'); ++ if (p) ++ *p = '\0'; ++ err = kstrtol(a + sizeof(DbgaufsXi_PREFIX) - 1, 10, &l); ++ if (unlikely(err)) ++ goto out; ++ bindex = l; ++ idx = 0; ++ if (p) { ++ err = kstrtol(p + 1, 10, &l); ++ if (unlikely(err)) ++ goto out; ++ idx = l; ++ } ++ ++ err = -ENOENT; ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ if (unlikely(bindex < 0 || bindex > au_sbbot(sb))) ++ goto out_si; ++ br = au_sbr(sb, bindex); ++ xi = br->br_xino; ++ if (unlikely(idx >= xi->xi_nfile)) ++ goto out_si; ++ xf = au_xino_file(xi, idx); ++ if (xf) ++ err = dbgaufs_xi_open(xf, file, /*do_fcnt*/1, ++ au_xino_count(br)); ++ ++out_si: ++ si_read_unlock(sb); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static const struct file_operations dbgaufs_xino_fop = { ++ .owner = THIS_MODULE, ++ .open = dbgaufs_xino_open, ++ .release = dbgaufs_xi_release, ++ .read = dbgaufs_xi_read ++}; ++ ++void dbgaufs_xino_del(struct au_branch *br) ++{ ++ struct dentry *dbgaufs; ++ ++ dbgaufs = br->br_dbgaufs; ++ if (!dbgaufs) ++ return; ++ ++ br->br_dbgaufs = NULL; ++ /* debugfs acquires the parent i_mutex */ ++ lockdep_off(); ++ debugfs_remove(dbgaufs); ++ lockdep_on(); ++} ++ ++void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ aufs_bindex_t bbot; ++ struct au_branch *br; ++ ++ if (!au_sbi(sb)->si_dbgaufs) ++ return; ++ ++ bbot = au_sbbot(sb); ++ for (; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ dbgaufs_xino_del(br); ++ } ++} ++ ++static void dbgaufs_br_do_add(struct super_block *sb, aufs_bindex_t bindex, ++ unsigned int idx, struct dentry *parent, ++ struct au_sbinfo *sbinfo) ++{ ++ struct au_branch *br; ++ struct dentry *d; ++ /* "xi" bindex(5) "-" idx(2) NULL */ ++ char name[sizeof(DbgaufsXi_PREFIX) + 8]; ++ ++ if (!idx) ++ snprintf(name, sizeof(name), DbgaufsXi_PREFIX "%d", bindex); ++ else ++ snprintf(name, sizeof(name), DbgaufsXi_PREFIX "%d-%u", ++ bindex, idx); ++ br = au_sbr(sb, bindex); ++ if (br->br_dbgaufs) { ++ struct qstr qstr = QSTR_INIT(name, strlen(name)); ++ ++ if (!au_qstreq(&br->br_dbgaufs->d_name, &qstr)) { ++ /* debugfs acquires the parent i_mutex */ ++ lockdep_off(); ++ d = debugfs_rename(parent, br->br_dbgaufs, parent, ++ name); ++ lockdep_on(); ++ if (unlikely(!d)) ++ pr_warn("failed renaming %pd/%s, ignored.\n", ++ parent, name); ++ } ++ } else { ++ lockdep_off(); ++ br->br_dbgaufs = debugfs_create_file(name, dbgaufs_mode, parent, ++ sbinfo, &dbgaufs_xino_fop); ++ lockdep_on(); ++ if (unlikely(!br->br_dbgaufs)) ++ pr_warn("failed creating %pd/%s, ignored.\n", ++ parent, name); ++ } ++} ++ ++static void dbgaufs_br_add(struct super_block *sb, aufs_bindex_t bindex, ++ struct dentry *parent, struct au_sbinfo *sbinfo) ++{ ++ struct au_branch *br; ++ struct au_xino *xi; ++ unsigned int u; ++ ++ br = au_sbr(sb, bindex); ++ xi = br->br_xino; ++ for (u = 0; u < xi->xi_nfile; u++) ++ dbgaufs_br_do_add(sb, bindex, u, parent, sbinfo); ++} ++ ++void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex, int topdown) ++{ ++ struct au_sbinfo *sbinfo; ++ struct dentry *parent; ++ aufs_bindex_t bbot; ++ ++ if (!au_opt_test(au_mntflags(sb), XINO)) ++ return; ++ ++ sbinfo = au_sbi(sb); ++ parent = sbinfo->si_dbgaufs; ++ if (!parent) ++ return; ++ ++ bbot = au_sbbot(sb); ++ if (topdown) ++ for (; bindex <= bbot; bindex++) ++ dbgaufs_br_add(sb, bindex, parent, sbinfo); ++ else ++ for (; bbot >= bindex; bbot--) ++ dbgaufs_br_add(sb, bbot, parent, sbinfo); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_EXPORT ++static int dbgaufs_xigen_open(struct inode *inode, struct file *file) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ err = dbgaufs_xi_open(sbinfo->si_xigen, file, /*do_fcnt*/0, /*cnt*/0); ++ si_read_unlock(sb); ++ return err; ++} ++ ++static const struct file_operations dbgaufs_xigen_fop = { ++ .owner = THIS_MODULE, ++ .open = dbgaufs_xigen_open, ++ .release = dbgaufs_xi_release, ++ .read = dbgaufs_xi_read ++}; ++ ++static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo) ++{ ++ int err; ++ ++ /* ++ * This function is a dynamic '__init' function actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++ ++ err = -EIO; ++ sbinfo->si_dbgaufs_xigen = debugfs_create_file ++ ("xigen", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, ++ &dbgaufs_xigen_fop); ++ if (sbinfo->si_dbgaufs_xigen) ++ err = 0; ++ ++ return err; ++} ++#else ++static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo) ++{ ++ return 0; ++} ++#endif /* CONFIG_AUFS_EXPORT */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++void dbgaufs_si_fin(struct au_sbinfo *sbinfo) ++{ ++ /* ++ * This function is a dynamic '__fin' function actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++ ++ debugfs_remove_recursive(sbinfo->si_dbgaufs); ++ sbinfo->si_dbgaufs = NULL; ++} ++ ++int dbgaufs_si_init(struct au_sbinfo *sbinfo) ++{ ++ int err; ++ char name[SysaufsSiNameLen]; ++ ++ /* ++ * This function is a dynamic '__init' function actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++ ++ err = -ENOENT; ++ if (!dbgaufs) { ++ AuErr1("/debug/aufs is uninitialized\n"); ++ goto out; ++ } ++ ++ err = -EIO; ++ sysaufs_name(sbinfo, name); ++ sbinfo->si_dbgaufs = debugfs_create_dir(name, dbgaufs); ++ if (unlikely(!sbinfo->si_dbgaufs)) ++ goto out; ++ ++ /* regardless plink/noplink option */ ++ sbinfo->si_dbgaufs_plink = debugfs_create_file ++ ("plink", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, ++ &dbgaufs_plink_fop); ++ if (unlikely(!sbinfo->si_dbgaufs_plink)) ++ goto out_dir; ++ ++ /* regardless xino/noxino option */ ++ sbinfo->si_dbgaufs_xib = debugfs_create_file ++ ("xib", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, ++ &dbgaufs_xib_fop); ++ if (unlikely(!sbinfo->si_dbgaufs_xib)) ++ goto out_dir; ++ ++ err = dbgaufs_xigen_init(sbinfo); ++ if (!err) ++ goto out; /* success */ ++ ++out_dir: ++ dbgaufs_si_fin(sbinfo); ++out: ++ if (unlikely(err)) ++ pr_err("debugfs/aufs failed\n"); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void dbgaufs_fin(void) ++{ ++ debugfs_remove(dbgaufs); ++} ++ ++int __init dbgaufs_init(void) ++{ ++ int err; ++ ++ err = -EIO; ++ dbgaufs = debugfs_create_dir(AUFS_NAME, NULL); ++ if (dbgaufs) ++ err = 0; ++ return err; ++} +diff -Naur null/fs/aufs/dbgaufs.h linux-5.15.36/fs/aufs/dbgaufs.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/dbgaufs.h 2022-05-10 16:51:39.867744220 +0300 +@@ -0,0 +1,53 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * debugfs interface ++ */ ++ ++#ifndef __DBGAUFS_H__ ++#define __DBGAUFS_H__ ++ ++#ifdef __KERNEL__ ++ ++struct super_block; ++struct au_sbinfo; ++struct au_branch; ++ ++#ifdef CONFIG_DEBUG_FS ++/* dbgaufs.c */ ++void dbgaufs_xino_del(struct au_branch *br); ++void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex); ++void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex, int topdown); ++void dbgaufs_si_fin(struct au_sbinfo *sbinfo); ++int dbgaufs_si_init(struct au_sbinfo *sbinfo); ++void dbgaufs_fin(void); ++int __init dbgaufs_init(void); ++#else ++AuStubVoid(dbgaufs_xino_del, struct au_branch *br) ++AuStubVoid(dbgaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex) ++AuStubVoid(dbgaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex, ++ int topdown) ++AuStubVoid(dbgaufs_si_fin, struct au_sbinfo *sbinfo) ++AuStubInt0(dbgaufs_si_init, struct au_sbinfo *sbinfo) ++AuStubVoid(dbgaufs_fin, void) ++AuStubInt0(__init dbgaufs_init, void) ++#endif /* CONFIG_DEBUG_FS */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __DBGAUFS_H__ */ +diff -Naur null/fs/aufs/dcsub.c linux-5.15.36/fs/aufs/dcsub.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/dcsub.c 2022-05-10 16:51:39.867744220 +0300 +@@ -0,0 +1,225 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * sub-routines for dentry cache ++ */ ++ ++#include "aufs.h" ++ ++static void au_dpage_free(struct au_dpage *dpage) ++{ ++ int i; ++ struct dentry **p; ++ ++ p = dpage->dentries; ++ for (i = 0; i < dpage->ndentry; i++) ++ dput(*p++); ++ free_page((unsigned long)dpage->dentries); ++} ++ ++int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp) ++{ ++ int err; ++ void *p; ++ ++ err = -ENOMEM; ++ dpages->dpages = kmalloc(sizeof(*dpages->dpages), gfp); ++ if (unlikely(!dpages->dpages)) ++ goto out; ++ ++ p = (void *)__get_free_page(gfp); ++ if (unlikely(!p)) ++ goto out_dpages; ++ ++ dpages->dpages[0].ndentry = 0; ++ dpages->dpages[0].dentries = p; ++ dpages->ndpage = 1; ++ return 0; /* success */ ++ ++out_dpages: ++ au_kfree_try_rcu(dpages->dpages); ++out: ++ return err; ++} ++ ++void au_dpages_free(struct au_dcsub_pages *dpages) ++{ ++ int i; ++ struct au_dpage *p; ++ ++ p = dpages->dpages; ++ for (i = 0; i < dpages->ndpage; i++) ++ au_dpage_free(p++); ++ au_kfree_try_rcu(dpages->dpages); ++} ++ ++static int au_dpages_append(struct au_dcsub_pages *dpages, ++ struct dentry *dentry, gfp_t gfp) ++{ ++ int err, sz; ++ struct au_dpage *dpage; ++ void *p; ++ ++ dpage = dpages->dpages + dpages->ndpage - 1; ++ sz = PAGE_SIZE / sizeof(dentry); ++ if (unlikely(dpage->ndentry >= sz)) { ++ AuLabel(new dpage); ++ err = -ENOMEM; ++ sz = dpages->ndpage * sizeof(*dpages->dpages); ++ p = au_kzrealloc(dpages->dpages, sz, ++ sz + sizeof(*dpages->dpages), gfp, ++ /*may_shrink*/0); ++ if (unlikely(!p)) ++ goto out; ++ ++ dpages->dpages = p; ++ dpage = dpages->dpages + dpages->ndpage; ++ p = (void *)__get_free_page(gfp); ++ if (unlikely(!p)) ++ goto out; ++ ++ dpage->ndentry = 0; ++ dpage->dentries = p; ++ dpages->ndpage++; ++ } ++ ++ AuDebugOn(au_dcount(dentry) <= 0); ++ dpage->dentries[dpage->ndentry++] = dget_dlock(dentry); ++ return 0; /* success */ ++ ++out: ++ return err; ++} ++ ++/* todo: BAD approach */ ++/* copied from linux/fs/dcache.c */ ++enum d_walk_ret { ++ D_WALK_CONTINUE, ++ D_WALK_QUIT, ++ D_WALK_NORETRY, ++ D_WALK_SKIP, ++}; ++ ++extern void d_walk(struct dentry *parent, void *data, ++ enum d_walk_ret (*enter)(void *, struct dentry *)); ++ ++struct ac_dpages_arg { ++ int err; ++ struct au_dcsub_pages *dpages; ++ struct super_block *sb; ++ au_dpages_test test; ++ void *arg; ++}; ++ ++static enum d_walk_ret au_call_dpages_append(void *_arg, struct dentry *dentry) ++{ ++ enum d_walk_ret ret; ++ struct ac_dpages_arg *arg = _arg; ++ ++ ret = D_WALK_CONTINUE; ++ if (dentry->d_sb == arg->sb ++ && !IS_ROOT(dentry) ++ && au_dcount(dentry) > 0 ++ && au_di(dentry) ++ && (!arg->test || arg->test(dentry, arg->arg))) { ++ arg->err = au_dpages_append(arg->dpages, dentry, GFP_ATOMIC); ++ if (unlikely(arg->err)) ++ ret = D_WALK_QUIT; ++ } ++ ++ return ret; ++} ++ ++int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, ++ au_dpages_test test, void *arg) ++{ ++ struct ac_dpages_arg args = { ++ .err = 0, ++ .dpages = dpages, ++ .sb = root->d_sb, ++ .test = test, ++ .arg = arg ++ }; ++ ++ d_walk(root, &args, au_call_dpages_append); ++ ++ return args.err; ++} ++ ++int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry, ++ int do_include, au_dpages_test test, void *arg) ++{ ++ int err; ++ ++ err = 0; ++ write_seqlock(&rename_lock); ++ spin_lock(&dentry->d_lock); ++ if (do_include ++ && au_dcount(dentry) > 0 ++ && (!test || test(dentry, arg))) ++ err = au_dpages_append(dpages, dentry, GFP_ATOMIC); ++ spin_unlock(&dentry->d_lock); ++ if (unlikely(err)) ++ goto out; ++ ++ /* ++ * RCU for vfsmount is unnecessary since this is a traverse in a single ++ * mount ++ */ ++ while (!IS_ROOT(dentry)) { ++ dentry = dentry->d_parent; /* rename_lock is locked */ ++ spin_lock(&dentry->d_lock); ++ if (au_dcount(dentry) > 0 ++ && (!test || test(dentry, arg))) ++ err = au_dpages_append(dpages, dentry, GFP_ATOMIC); ++ spin_unlock(&dentry->d_lock); ++ if (unlikely(err)) ++ break; ++ } ++ ++out: ++ write_sequnlock(&rename_lock); ++ return err; ++} ++ ++static inline int au_dcsub_dpages_aufs(struct dentry *dentry, void *arg) ++{ ++ return au_di(dentry) && dentry->d_sb == arg; ++} ++ ++int au_dcsub_pages_rev_aufs(struct au_dcsub_pages *dpages, ++ struct dentry *dentry, int do_include) ++{ ++ return au_dcsub_pages_rev(dpages, dentry, do_include, ++ au_dcsub_dpages_aufs, dentry->d_sb); ++} ++ ++int au_test_subdir(struct dentry *d1, struct dentry *d2) ++{ ++ struct path path[2] = { ++ { ++ .dentry = d1 ++ }, ++ { ++ .dentry = d2 ++ } ++ }; ++ ++ return path_is_under(path + 0, path + 1); ++} +diff -Naur null/fs/aufs/dcsub.h linux-5.15.36/fs/aufs/dcsub.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/dcsub.h 2022-05-10 16:51:39.867744220 +0300 +@@ -0,0 +1,137 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * sub-routines for dentry cache ++ */ ++ ++#ifndef __AUFS_DCSUB_H__ ++#define __AUFS_DCSUB_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++ ++struct au_dpage { ++ int ndentry; ++ struct dentry **dentries; ++}; ++ ++struct au_dcsub_pages { ++ int ndpage; ++ struct au_dpage *dpages; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dcsub.c */ ++int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp); ++void au_dpages_free(struct au_dcsub_pages *dpages); ++typedef int (*au_dpages_test)(struct dentry *dentry, void *arg); ++int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, ++ au_dpages_test test, void *arg); ++int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry, ++ int do_include, au_dpages_test test, void *arg); ++int au_dcsub_pages_rev_aufs(struct au_dcsub_pages *dpages, ++ struct dentry *dentry, int do_include); ++int au_test_subdir(struct dentry *d1, struct dentry *d2); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * todo: in linux-3.13, several similar (but faster) helpers are added to ++ * include/linux/dcache.h. Try them (in the future). ++ */ ++ ++static inline int au_d_hashed_positive(struct dentry *d) ++{ ++ int err; ++ struct inode *inode = d_inode(d); ++ ++ err = 0; ++ if (unlikely(d_unhashed(d) ++ || d_is_negative(d) ++ || !inode->i_nlink)) ++ err = -ENOENT; ++ return err; ++} ++ ++static inline int au_d_linkable(struct dentry *d) ++{ ++ int err; ++ struct inode *inode = d_inode(d); ++ ++ err = au_d_hashed_positive(d); ++ if (err ++ && d_is_positive(d) ++ && (inode->i_state & I_LINKABLE)) ++ err = 0; ++ return err; ++} ++ ++static inline int au_d_alive(struct dentry *d) ++{ ++ int err; ++ struct inode *inode; ++ ++ err = 0; ++ if (!IS_ROOT(d)) ++ err = au_d_hashed_positive(d); ++ else { ++ inode = d_inode(d); ++ if (unlikely(d_unlinked(d) ++ || d_is_negative(d) ++ || !inode->i_nlink)) ++ err = -ENOENT; ++ } ++ return err; ++} ++ ++static inline int au_alive_dir(struct dentry *d) ++{ ++ int err; ++ ++ err = au_d_alive(d); ++ if (unlikely(err || IS_DEADDIR(d_inode(d)))) ++ err = -ENOENT; ++ return err; ++} ++ ++static inline int au_qstreq(struct qstr *a, struct qstr *b) ++{ ++ return a->len == b->len ++ && !memcmp(a->name, b->name, a->len); ++} ++ ++/* ++ * by the commit ++ * 360f547 2015-01-25 dcache: let the dentry count go down to zero without ++ * taking d_lock ++ * the type of d_lockref.count became int, but the inlined function d_count() ++ * still returns unsigned int. ++ * I don't know why. Maybe it is for every d_count() users? ++ * Anyway au_dcount() lives on. ++ */ ++static inline int au_dcount(struct dentry *d) ++{ ++ return (int)d_count(d); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DCSUB_H__ */ +diff -Naur null/fs/aufs/debug.c linux-5.15.36/fs/aufs/debug.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/debug.c 2022-05-10 16:51:39.868744219 +0300 +@@ -0,0 +1,444 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * debug print functions ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* Returns 0, or -errno. arg is in kp->arg. */ ++static int param_atomic_t_set(const char *val, const struct kernel_param *kp) ++{ ++ int err, n; ++ ++ err = kstrtoint(val, 0, &n); ++ if (!err) { ++ if (n > 0) ++ au_debug_on(); ++ else ++ au_debug_off(); ++ } ++ return err; ++} ++ ++/* Returns length written or -errno. Buffer is 4k (ie. be short!) */ ++static int param_atomic_t_get(char *buffer, const struct kernel_param *kp) ++{ ++ atomic_t *a; ++ ++ a = kp->arg; ++ return sprintf(buffer, "%d", atomic_read(a)); ++} ++ ++static struct kernel_param_ops param_ops_atomic_t = { ++ .set = param_atomic_t_set, ++ .get = param_atomic_t_get ++ /* void (*free)(void *arg) */ ++}; ++ ++atomic_t aufs_debug = ATOMIC_INIT(0); ++MODULE_PARM_DESC(debug, "debug print"); ++module_param_named(debug, aufs_debug, atomic_t, 0664); ++ ++DEFINE_MUTEX(au_dbg_mtx); /* just to serialize the dbg msgs */ ++char *au_plevel = KERN_DEBUG; ++#define dpri(fmt, ...) do { \ ++ if ((au_plevel \ ++ && strcmp(au_plevel, KERN_DEBUG)) \ ++ || au_debug_test()) \ ++ printk("%s" fmt, au_plevel, ##__VA_ARGS__); \ ++} while (0) ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_dpri_whlist(struct au_nhash *whlist) ++{ ++ unsigned long ul, n; ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ ++ n = whlist->nh_num; ++ head = whlist->nh_head; ++ for (ul = 0; ul < n; ul++) { ++ hlist_for_each_entry(pos, head, wh_hash) ++ dpri("b%d, %.*s, %d\n", ++ pos->wh_bindex, ++ pos->wh_str.len, pos->wh_str.name, ++ pos->wh_str.len); ++ head++; ++ } ++} ++ ++void au_dpri_vdir(struct au_vdir *vdir) ++{ ++ unsigned long ul; ++ union au_vdir_deblk_p p; ++ unsigned char *o; ++ ++ if (!vdir || IS_ERR(vdir)) { ++ dpri("err %ld\n", PTR_ERR(vdir)); ++ return; ++ } ++ ++ dpri("deblk %u, nblk %lu, deblk %p, last{%lu, %p}, ver %llu\n", ++ vdir->vd_deblk_sz, vdir->vd_nblk, vdir->vd_deblk, ++ vdir->vd_last.ul, vdir->vd_last.p.deblk, vdir->vd_version); ++ for (ul = 0; ul < vdir->vd_nblk; ul++) { ++ p.deblk = vdir->vd_deblk[ul]; ++ o = p.deblk; ++ dpri("[%lu]: %p\n", ul, o); ++ } ++} ++ ++static int do_pri_inode(aufs_bindex_t bindex, struct inode *inode, int hn, ++ struct dentry *wh) ++{ ++ char *n = NULL; ++ int l = 0; ++ ++ if (!inode || IS_ERR(inode)) { ++ dpri("i%d: err %ld\n", bindex, PTR_ERR(inode)); ++ return -1; ++ } ++ ++ /* the type of i_blocks depends upon CONFIG_LBDAF */ ++ BUILD_BUG_ON(sizeof(inode->i_blocks) != sizeof(unsigned long) ++ && sizeof(inode->i_blocks) != sizeof(u64)); ++ if (wh) { ++ n = (void *)wh->d_name.name; ++ l = wh->d_name.len; ++ } ++ ++ dpri("i%d: %p, i%lu, %s, cnt %d, nl %u, 0%o, sz %llu, blk %llu," ++ " hn %d, ct %lld, np %lu, st 0x%lx, f 0x%x, v %llu, g %x%s%.*s\n", ++ bindex, inode, ++ inode->i_ino, inode->i_sb ? au_sbtype(inode->i_sb) : "??", ++ atomic_read(&inode->i_count), inode->i_nlink, inode->i_mode, ++ i_size_read(inode), (unsigned long long)inode->i_blocks, ++ hn, (long long)timespec64_to_ns(&inode->i_ctime) & 0x0ffff, ++ inode->i_mapping ? inode->i_mapping->nrpages : 0, ++ inode->i_state, inode->i_flags, inode_peek_iversion(inode), ++ inode->i_generation, ++ l ? ", wh " : "", l, n); ++ return 0; ++} ++ ++void au_dpri_inode(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ struct au_hinode *hi; ++ aufs_bindex_t bindex; ++ int err, hn; ++ ++ err = do_pri_inode(-1, inode, -1, NULL); ++ if (err || !au_test_aufs(inode->i_sb) || au_is_bad_inode(inode)) ++ return; ++ ++ iinfo = au_ii(inode); ++ dpri("i-1: btop %d, bbot %d, gen %d\n", ++ iinfo->ii_btop, iinfo->ii_bbot, au_iigen(inode, NULL)); ++ if (iinfo->ii_btop < 0) ++ return; ++ hn = 0; ++ for (bindex = iinfo->ii_btop; bindex <= iinfo->ii_bbot; bindex++) { ++ hi = au_hinode(iinfo, bindex); ++ hn = !!au_hn(hi); ++ do_pri_inode(bindex, hi->hi_inode, hn, hi->hi_whdentry); ++ } ++} ++ ++void au_dpri_dalias(struct inode *inode) ++{ ++ struct dentry *d; ++ ++ spin_lock(&inode->i_lock); ++ hlist_for_each_entry(d, &inode->i_dentry, d_u.d_alias) ++ au_dpri_dentry(d); ++ spin_unlock(&inode->i_lock); ++} ++ ++static int do_pri_dentry(aufs_bindex_t bindex, struct dentry *dentry) ++{ ++ struct dentry *wh = NULL; ++ int hn; ++ struct inode *inode; ++ struct au_iinfo *iinfo; ++ struct au_hinode *hi; ++ ++ if (!dentry || IS_ERR(dentry)) { ++ dpri("d%d: err %ld\n", bindex, PTR_ERR(dentry)); ++ return -1; ++ } ++ /* do not call dget_parent() here */ ++ /* note: access d_xxx without d_lock */ ++ dpri("d%d: %p, %pd2?, %s, cnt %d, flags 0x%x, %shashed\n", ++ bindex, dentry, dentry, ++ dentry->d_sb ? au_sbtype(dentry->d_sb) : "??", ++ au_dcount(dentry), dentry->d_flags, ++ d_unhashed(dentry) ? "un" : ""); ++ hn = -1; ++ inode = NULL; ++ if (d_is_positive(dentry)) ++ inode = d_inode(dentry); ++ if (inode ++ && au_test_aufs(dentry->d_sb) ++ && bindex >= 0 ++ && !au_is_bad_inode(inode)) { ++ iinfo = au_ii(inode); ++ hi = au_hinode(iinfo, bindex); ++ hn = !!au_hn(hi); ++ wh = hi->hi_whdentry; ++ } ++ do_pri_inode(bindex, inode, hn, wh); ++ return 0; ++} ++ ++void au_dpri_dentry(struct dentry *dentry) ++{ ++ struct au_dinfo *dinfo; ++ aufs_bindex_t bindex; ++ int err; ++ ++ err = do_pri_dentry(-1, dentry); ++ if (err || !au_test_aufs(dentry->d_sb)) ++ return; ++ ++ dinfo = au_di(dentry); ++ if (!dinfo) ++ return; ++ dpri("d-1: btop %d, bbot %d, bwh %d, bdiropq %d, gen %d, tmp %d\n", ++ dinfo->di_btop, dinfo->di_bbot, ++ dinfo->di_bwh, dinfo->di_bdiropq, au_digen(dentry), ++ dinfo->di_tmpfile); ++ if (dinfo->di_btop < 0) ++ return; ++ for (bindex = dinfo->di_btop; bindex <= dinfo->di_bbot; bindex++) ++ do_pri_dentry(bindex, au_hdentry(dinfo, bindex)->hd_dentry); ++} ++ ++static int do_pri_file(aufs_bindex_t bindex, struct file *file) ++{ ++ char a[32]; ++ ++ if (!file || IS_ERR(file)) { ++ dpri("f%d: err %ld\n", bindex, PTR_ERR(file)); ++ return -1; ++ } ++ a[0] = 0; ++ if (bindex < 0 ++ && !IS_ERR_OR_NULL(file->f_path.dentry) ++ && au_test_aufs(file->f_path.dentry->d_sb) ++ && au_fi(file)) ++ snprintf(a, sizeof(a), ", gen %d, mmapped %d", ++ au_figen(file), atomic_read(&au_fi(file)->fi_mmapped)); ++ dpri("f%d: mode 0x%x, flags 0%o, cnt %ld, v %llu, pos %llu%s\n", ++ bindex, file->f_mode, file->f_flags, (long)file_count(file), ++ file->f_version, file->f_pos, a); ++ if (!IS_ERR_OR_NULL(file->f_path.dentry)) ++ do_pri_dentry(bindex, file->f_path.dentry); ++ return 0; ++} ++ ++void au_dpri_file(struct file *file) ++{ ++ struct au_finfo *finfo; ++ struct au_fidir *fidir; ++ struct au_hfile *hfile; ++ aufs_bindex_t bindex; ++ int err; ++ ++ err = do_pri_file(-1, file); ++ if (err ++ || IS_ERR_OR_NULL(file->f_path.dentry) ++ || !au_test_aufs(file->f_path.dentry->d_sb)) ++ return; ++ ++ finfo = au_fi(file); ++ if (!finfo) ++ return; ++ if (finfo->fi_btop < 0) ++ return; ++ fidir = finfo->fi_hdir; ++ if (!fidir) ++ do_pri_file(finfo->fi_btop, finfo->fi_htop.hf_file); ++ else ++ for (bindex = finfo->fi_btop; ++ bindex >= 0 && bindex <= fidir->fd_bbot; ++ bindex++) { ++ hfile = fidir->fd_hfile + bindex; ++ do_pri_file(bindex, hfile ? hfile->hf_file : NULL); ++ } ++} ++ ++static int do_pri_br(aufs_bindex_t bindex, struct au_branch *br) ++{ ++ struct vfsmount *mnt; ++ struct super_block *sb; ++ ++ if (!br || IS_ERR(br)) ++ goto out; ++ mnt = au_br_mnt(br); ++ if (!mnt || IS_ERR(mnt)) ++ goto out; ++ sb = mnt->mnt_sb; ++ if (!sb || IS_ERR(sb)) ++ goto out; ++ ++ dpri("s%d: {perm 0x%x, id %d, wbr %p}, " ++ "%s, dev 0x%02x%02x, flags 0x%lx, cnt %d, active %d, " ++ "xino %d\n", ++ bindex, br->br_perm, br->br_id, br->br_wbr, ++ au_sbtype(sb), MAJOR(sb->s_dev), MINOR(sb->s_dev), ++ sb->s_flags, sb->s_count, ++ atomic_read(&sb->s_active), ++ !!au_xino_file(br->br_xino, /*idx*/-1)); ++ return 0; ++ ++out: ++ dpri("s%d: err %ld\n", bindex, PTR_ERR(br)); ++ return -1; ++} ++ ++void au_dpri_sb(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ aufs_bindex_t bindex; ++ int err; ++ /* to reduce stack size */ ++ struct { ++ struct vfsmount mnt; ++ struct au_branch fake; ++ } *a; ++ ++ /* this function can be called from magic sysrq */ ++ a = kzalloc(sizeof(*a), GFP_ATOMIC); ++ if (unlikely(!a)) { ++ dpri("no memory\n"); ++ return; ++ } ++ ++ a->mnt.mnt_sb = sb; ++ a->fake.br_path.mnt = &a->mnt; ++ err = do_pri_br(-1, &a->fake); ++ au_kfree_rcu(a); ++ dpri("dev 0x%x\n", sb->s_dev); ++ if (err || !au_test_aufs(sb)) ++ return; ++ ++ sbinfo = au_sbi(sb); ++ if (!sbinfo) ++ return; ++ dpri("nw %d, gen %u, kobj %d\n", ++ atomic_read(&sbinfo->si_nowait.nw_len), sbinfo->si_generation, ++ kref_read(&sbinfo->si_kobj.kref)); ++ for (bindex = 0; bindex <= sbinfo->si_bbot; bindex++) ++ do_pri_br(bindex, sbinfo->si_branch[0 + bindex]); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void __au_dbg_verify_dinode(struct dentry *dentry, const char *func, int line) ++{ ++ struct inode *h_inode, *inode = d_inode(dentry); ++ struct dentry *h_dentry; ++ aufs_bindex_t bindex, bbot, bi; ++ ++ if (!inode /* || au_di(dentry)->di_lsc == AuLsc_DI_TMP */) ++ return; ++ ++ bbot = au_dbbot(dentry); ++ bi = au_ibbot(inode); ++ if (bi < bbot) ++ bbot = bi; ++ bindex = au_dbtop(dentry); ++ bi = au_ibtop(inode); ++ if (bi > bindex) ++ bindex = bi; ++ ++ for (; bindex <= bbot; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ h_inode = au_h_iptr(inode, bindex); ++ if (unlikely(h_inode != d_inode(h_dentry))) { ++ au_debug_on(); ++ AuDbg("b%d, %s:%d\n", bindex, func, line); ++ AuDbgDentry(dentry); ++ AuDbgInode(inode); ++ au_debug_off(); ++ if (au_test_fuse(h_inode->i_sb)) ++ WARN_ON_ONCE(1); ++ else ++ BUG(); ++ } ++ } ++} ++ ++void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen) ++{ ++ int err, i, j; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ AuDebugOn(err); ++ err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/1); ++ AuDebugOn(err); ++ for (i = dpages.ndpage - 1; !err && i >= 0; i--) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ for (j = dpage->ndentry - 1; !err && j >= 0; j--) ++ AuDebugOn(au_digen_test(dentries[j], sigen)); ++ } ++ au_dpages_free(&dpages); ++} ++ ++void au_dbg_verify_kthread(void) ++{ ++ if (au_wkq_test()) { ++ au_dbg_blocked(); ++ /* ++ * It may be recursive, but udba=notify between two aufs mounts, ++ * where a single ro branch is shared, is not a problem. ++ */ ++ /* WARN_ON(1); */ ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int __init au_debug_init(void) ++{ ++ aufs_bindex_t bindex; ++ struct au_vdir_destr destr; ++ ++ bindex = -1; ++ AuDebugOn(bindex >= 0); ++ ++ destr.len = -1; ++ AuDebugOn(destr.len < NAME_MAX); ++ ++#ifdef CONFIG_4KSTACKS ++ pr_warn("CONFIG_4KSTACKS is defined.\n"); ++#endif ++ ++ return 0; ++} +diff -Naur null/fs/aufs/debug.h linux-5.15.36/fs/aufs/debug.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/debug.h 2022-05-10 16:51:39.868744219 +0300 +@@ -0,0 +1,226 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * debug print functions ++ */ ++ ++#ifndef __AUFS_DEBUG_H__ ++#define __AUFS_DEBUG_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_AUFS_DEBUG ++#define AuDebugOn(a) BUG_ON(a) ++ ++/* module parameter */ ++extern atomic_t aufs_debug; ++static inline void au_debug_on(void) ++{ ++ atomic_inc(&aufs_debug); ++} ++static inline void au_debug_off(void) ++{ ++ atomic_dec_if_positive(&aufs_debug); ++} ++ ++static inline int au_debug_test(void) ++{ ++ return atomic_read(&aufs_debug) > 0; ++} ++#else ++#define AuDebugOn(a) do {} while (0) ++AuStubVoid(au_debug_on, void) ++AuStubVoid(au_debug_off, void) ++AuStubInt0(au_debug_test, void) ++#endif /* CONFIG_AUFS_DEBUG */ ++ ++#define param_check_atomic_t(name, p) __param_check(name, p, atomic_t) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* debug print */ ++ ++#define AuDbg(fmt, ...) do { \ ++ if (au_debug_test()) \ ++ pr_debug("DEBUG: " fmt, ##__VA_ARGS__); \ ++} while (0) ++#define AuLabel(l) AuDbg(#l "\n") ++#define AuIOErr(fmt, ...) pr_err("I/O Error, " fmt, ##__VA_ARGS__) ++#define AuWarn1(fmt, ...) do { \ ++ static unsigned char _c; \ ++ if (!_c++) \ ++ pr_warn(fmt, ##__VA_ARGS__); \ ++} while (0) ++ ++#define AuErr1(fmt, ...) do { \ ++ static unsigned char _c; \ ++ if (!_c++) \ ++ pr_err(fmt, ##__VA_ARGS__); \ ++} while (0) ++ ++#define AuIOErr1(fmt, ...) do { \ ++ static unsigned char _c; \ ++ if (!_c++) \ ++ AuIOErr(fmt, ##__VA_ARGS__); \ ++} while (0) ++ ++#define AuUnsupportMsg "This operation is not supported." \ ++ " Please report this application to aufs-users ML." ++#define AuUnsupport(fmt, ...) do { \ ++ pr_err(AuUnsupportMsg "\n" fmt, ##__VA_ARGS__); \ ++ dump_stack(); \ ++} while (0) ++ ++#define AuTraceErr(e) do { \ ++ if (unlikely((e) < 0)) \ ++ AuDbg("err %d\n", (int)(e)); \ ++} while (0) ++ ++#define AuTraceErrPtr(p) do { \ ++ if (IS_ERR(p)) \ ++ AuDbg("err %ld\n", PTR_ERR(p)); \ ++} while (0) ++ ++/* dirty macros for debug print, use with "%.*s" and caution */ ++#define AuLNPair(qstr) (qstr)->len, (qstr)->name ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct dentry; ++#ifdef CONFIG_AUFS_DEBUG ++extern struct mutex au_dbg_mtx; ++extern char *au_plevel; ++struct au_nhash; ++void au_dpri_whlist(struct au_nhash *whlist); ++struct au_vdir; ++void au_dpri_vdir(struct au_vdir *vdir); ++struct inode; ++void au_dpri_inode(struct inode *inode); ++void au_dpri_dalias(struct inode *inode); ++void au_dpri_dentry(struct dentry *dentry); ++struct file; ++void au_dpri_file(struct file *filp); ++struct super_block; ++void au_dpri_sb(struct super_block *sb); ++ ++#define au_dbg_verify_dinode(d) __au_dbg_verify_dinode(d, __func__, __LINE__) ++void __au_dbg_verify_dinode(struct dentry *dentry, const char *func, int line); ++void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen); ++void au_dbg_verify_kthread(void); ++ ++int __init au_debug_init(void); ++ ++#define AuDbgWhlist(w) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#w "\n"); \ ++ au_dpri_whlist(w); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgVdir(v) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#v "\n"); \ ++ au_dpri_vdir(v); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgInode(i) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#i "\n"); \ ++ au_dpri_inode(i); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgDAlias(i) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#i "\n"); \ ++ au_dpri_dalias(i); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgDentry(d) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#d "\n"); \ ++ au_dpri_dentry(d); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgFile(f) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#f "\n"); \ ++ au_dpri_file(f); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgSb(sb) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#sb "\n"); \ ++ au_dpri_sb(sb); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgSym(addr) do { \ ++ char sym[KSYM_SYMBOL_LEN]; \ ++ sprint_symbol(sym, (unsigned long)addr); \ ++ AuDbg("%s\n", sym); \ ++} while (0) ++#else ++AuStubVoid(au_dbg_verify_dinode, struct dentry *dentry) ++AuStubVoid(au_dbg_verify_gen, struct dentry *parent, unsigned int sigen) ++AuStubVoid(au_dbg_verify_kthread, void) ++AuStubInt0(__init au_debug_init, void) ++ ++#define AuDbgWhlist(w) do {} while (0) ++#define AuDbgVdir(v) do {} while (0) ++#define AuDbgInode(i) do {} while (0) ++#define AuDbgDAlias(i) do {} while (0) ++#define AuDbgDentry(d) do {} while (0) ++#define AuDbgFile(f) do {} while (0) ++#define AuDbgSb(sb) do {} while (0) ++#define AuDbgSym(addr) do {} while (0) ++#endif /* CONFIG_AUFS_DEBUG */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_MAGIC_SYSRQ ++int __init au_sysrq_init(void); ++void au_sysrq_fin(void); ++ ++#ifdef CONFIG_HW_CONSOLE ++#define au_dbg_blocked() do { \ ++ WARN_ON(1); \ ++ handle_sysrq('w'); \ ++} while (0) ++#else ++AuStubVoid(au_dbg_blocked, void) ++#endif ++ ++#else ++AuStubInt0(__init au_sysrq_init, void) ++AuStubVoid(au_sysrq_fin, void) ++AuStubVoid(au_dbg_blocked, void) ++#endif /* CONFIG_AUFS_MAGIC_SYSRQ */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DEBUG_H__ */ +diff -Naur null/fs/aufs/dentry.c linux-5.15.36/fs/aufs/dentry.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/dentry.c 2022-05-10 16:51:39.868744219 +0300 +@@ -0,0 +1,1168 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * lookup and dentry operations ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* ++ * returns positive/negative dentry, NULL or an error. ++ * NULL means whiteout-ed or not-found. ++ */ ++static struct dentry* ++au_do_lookup(struct dentry *h_parent, struct dentry *dentry, ++ aufs_bindex_t bindex, struct au_do_lookup_args *args) ++{ ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct au_branch *br; ++ struct user_namespace *h_userns; ++ struct path h_path; ++ int wh_found, opq; ++ unsigned char wh_able; ++ const unsigned char allow_neg = !!au_ftest_lkup(args->flags, ALLOW_NEG); ++ const unsigned char ignore_perm = !!au_ftest_lkup(args->flags, ++ IGNORE_PERM); ++ ++ wh_found = 0; ++ br = au_sbr(dentry->d_sb, bindex); ++ h_path.dentry = h_parent; ++ h_path.mnt = au_br_mnt(br); ++ h_userns = au_br_userns(br); ++ wh_able = !!au_br_whable(br->br_perm); ++ if (wh_able) ++ wh_found = au_wh_test(h_userns, &h_path, &args->whname, ++ ignore_perm); ++ h_dentry = ERR_PTR(wh_found); ++ if (!wh_found) ++ goto real_lookup; ++ if (unlikely(wh_found < 0)) ++ goto out; ++ ++ /* We found a whiteout */ ++ /* au_set_dbbot(dentry, bindex); */ ++ au_set_dbwh(dentry, bindex); ++ if (!allow_neg) ++ return NULL; /* success */ ++ ++real_lookup: ++ if (!ignore_perm) ++ h_dentry = vfsub_lkup_one(args->name, &h_path); ++ else ++ h_dentry = au_sio_lkup_one(h_userns, args->name, &h_path); ++ if (IS_ERR(h_dentry)) { ++ if (PTR_ERR(h_dentry) == -ENAMETOOLONG ++ && !allow_neg) ++ h_dentry = NULL; ++ goto out; ++ } ++ ++ h_inode = d_inode(h_dentry); ++ if (d_is_negative(h_dentry)) { ++ if (!allow_neg) ++ goto out_neg; ++ } else if (wh_found ++ || (args->type && args->type != (h_inode->i_mode & S_IFMT))) ++ goto out_neg; ++ else if (au_ftest_lkup(args->flags, DIRREN) ++ /* && h_inode */ ++ && !au_dr_lkup_h_ino(args, bindex, h_inode->i_ino)) { ++ AuDbg("b%d %pd ignored hi%llu\n", bindex, h_dentry, ++ (unsigned long long)h_inode->i_ino); ++ goto out_neg; ++ } ++ ++ if (au_dbbot(dentry) <= bindex) ++ au_set_dbbot(dentry, bindex); ++ if (au_dbtop(dentry) < 0 || bindex < au_dbtop(dentry)) ++ au_set_dbtop(dentry, bindex); ++ au_set_h_dptr(dentry, bindex, h_dentry); ++ ++ if (!d_is_dir(h_dentry) ++ || !wh_able ++ || (d_really_is_positive(dentry) && !d_is_dir(dentry))) ++ goto out; /* success */ ++ ++ h_path.dentry = h_dentry; ++ inode_lock_shared_nested(h_inode, AuLsc_I_CHILD); ++ opq = au_diropq_test(h_userns, &h_path); ++ inode_unlock_shared(h_inode); ++ if (opq > 0) ++ au_set_dbdiropq(dentry, bindex); ++ else if (unlikely(opq < 0)) { ++ au_set_h_dptr(dentry, bindex, NULL); ++ h_dentry = ERR_PTR(opq); ++ } ++ goto out; ++ ++out_neg: ++ dput(h_dentry); ++ h_dentry = NULL; ++out: ++ return h_dentry; ++} ++ ++static int au_test_shwh(struct super_block *sb, const struct qstr *name) ++{ ++ if (unlikely(!au_opt_test(au_mntflags(sb), SHWH) ++ && !strncmp(name->name, AUFS_WH_PFX, AUFS_WH_PFX_LEN))) ++ return -EPERM; ++ return 0; ++} ++ ++/* ++ * returns the number of lower positive dentries, ++ * otherwise an error. ++ * can be called at unlinking with @type is zero. ++ */ ++int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t btop, ++ unsigned int flags) ++{ ++ int npositive, err; ++ aufs_bindex_t bindex, btail, bdiropq; ++ unsigned char isdir, dirperm1, dirren; ++ struct au_do_lookup_args args = { ++ .flags = flags, ++ .name = &dentry->d_name ++ }; ++ struct dentry *parent; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ err = au_test_shwh(sb, args.name); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_wh_name_alloc(&args.whname, args.name); ++ if (unlikely(err)) ++ goto out; ++ ++ isdir = !!d_is_dir(dentry); ++ dirperm1 = !!au_opt_test(au_mntflags(sb), DIRPERM1); ++ dirren = !!au_opt_test(au_mntflags(sb), DIRREN); ++ if (dirren) ++ au_fset_lkup(args.flags, DIRREN); ++ ++ npositive = 0; ++ parent = dget_parent(dentry); ++ btail = au_dbtaildir(parent); ++ for (bindex = btop; bindex <= btail; bindex++) { ++ struct dentry *h_parent, *h_dentry; ++ struct inode *h_inode, *h_dir; ++ struct au_branch *br; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry) { ++ if (d_is_positive(h_dentry)) ++ npositive++; ++ break; ++ } ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || !d_is_dir(h_parent)) ++ continue; ++ ++ if (dirren) { ++ /* if the inum matches, then use the prepared name */ ++ err = au_dr_lkup_name(&args, bindex); ++ if (unlikely(err)) ++ goto out_parent; ++ } ++ ++ h_dir = d_inode(h_parent); ++ inode_lock_shared_nested(h_dir, AuLsc_I_PARENT); ++ h_dentry = au_do_lookup(h_parent, dentry, bindex, &args); ++ inode_unlock_shared(h_dir); ++ err = PTR_ERR(h_dentry); ++ if (IS_ERR(h_dentry)) ++ goto out_parent; ++ if (h_dentry) ++ au_fclr_lkup(args.flags, ALLOW_NEG); ++ if (dirperm1) ++ au_fset_lkup(args.flags, IGNORE_PERM); ++ ++ if (au_dbwh(dentry) == bindex) ++ break; ++ if (!h_dentry) ++ continue; ++ if (d_is_negative(h_dentry)) ++ continue; ++ h_inode = d_inode(h_dentry); ++ npositive++; ++ if (!args.type) ++ args.type = h_inode->i_mode & S_IFMT; ++ if (args.type != S_IFDIR) ++ break; ++ else if (isdir) { ++ /* the type of lower may be different */ ++ bdiropq = au_dbdiropq(dentry); ++ if (bdiropq >= 0 && bdiropq <= bindex) ++ break; ++ } ++ br = au_sbr(sb, bindex); ++ if (dirren ++ && au_dr_hino_test_add(&br->br_dirren, h_inode->i_ino, ++ /*add_ent*/NULL)) { ++ /* prepare next name to lookup */ ++ err = au_dr_lkup(&args, dentry, bindex); ++ if (unlikely(err)) ++ goto out_parent; ++ } ++ } ++ ++ if (npositive) { ++ AuLabel(positive); ++ au_update_dbtop(dentry); ++ } ++ err = npositive; ++ if (unlikely(!au_opt_test(au_mntflags(sb), UDBA_NONE) ++ && au_dbtop(dentry) < 0)) { ++ err = -EIO; ++ AuIOErr("both of real entry and whiteout found, %pd, err %d\n", ++ dentry, err); ++ } ++ ++out_parent: ++ dput(parent); ++ au_kfree_try_rcu(args.whname.name); ++ if (dirren) ++ au_dr_lkup_fin(&args); ++out: ++ return err; ++} ++ ++struct dentry *au_sio_lkup_one(struct user_namespace *userns, struct qstr *name, ++ struct path *ppath) ++{ ++ struct dentry *dentry; ++ int wkq_err; ++ ++ if (!au_test_h_perm_sio(userns, d_inode(ppath->dentry), MAY_EXEC)) ++ dentry = vfsub_lkup_one(name, ppath); ++ else { ++ struct vfsub_lkup_one_args args = { ++ .errp = &dentry, ++ .name = name, ++ .ppath = ppath ++ }; ++ ++ wkq_err = au_wkq_wait(vfsub_call_lkup_one, &args); ++ if (unlikely(wkq_err)) ++ dentry = ERR_PTR(wkq_err); ++ } ++ ++ return dentry; ++} ++ ++/* ++ * lookup @dentry on @bindex which should be negative. ++ */ ++int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex, int wh) ++{ ++ int err; ++ struct dentry *parent, *h_dentry; ++ struct au_branch *br; ++ struct user_namespace *h_userns; ++ struct path h_ppath; ++ ++ parent = dget_parent(dentry); ++ br = au_sbr(dentry->d_sb, bindex); ++ h_ppath.dentry = au_h_dptr(parent, bindex); ++ h_ppath.mnt = au_br_mnt(br); ++ h_userns = au_br_userns(br); ++ if (wh) ++ h_dentry = au_whtmp_lkup(h_ppath.dentry, br, &dentry->d_name); ++ else ++ h_dentry = au_sio_lkup_one(h_userns, &dentry->d_name, &h_ppath); ++ err = PTR_ERR(h_dentry); ++ if (IS_ERR(h_dentry)) ++ goto out; ++ if (unlikely(d_is_positive(h_dentry))) { ++ err = -EIO; ++ AuIOErr("%pd should be negative on b%d.\n", h_dentry, bindex); ++ dput(h_dentry); ++ goto out; ++ } ++ ++ err = 0; ++ if (bindex < au_dbtop(dentry)) ++ au_set_dbtop(dentry, bindex); ++ if (au_dbbot(dentry) < bindex) ++ au_set_dbbot(dentry, bindex); ++ au_set_h_dptr(dentry, bindex, h_dentry); ++ ++out: ++ dput(parent); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* subset of struct inode */ ++struct au_iattr { ++ unsigned long i_ino; ++ /* unsigned int i_nlink; */ ++ kuid_t i_uid; ++ kgid_t i_gid; ++ u64 i_version; ++/* ++ loff_t i_size; ++ blkcnt_t i_blocks; ++*/ ++ umode_t i_mode; ++}; ++ ++static void au_iattr_save(struct au_iattr *ia, struct inode *h_inode) ++{ ++ ia->i_ino = h_inode->i_ino; ++ /* ia->i_nlink = h_inode->i_nlink; */ ++ ia->i_uid = h_inode->i_uid; ++ ia->i_gid = h_inode->i_gid; ++ ia->i_version = inode_query_iversion(h_inode); ++/* ++ ia->i_size = h_inode->i_size; ++ ia->i_blocks = h_inode->i_blocks; ++*/ ++ ia->i_mode = (h_inode->i_mode & S_IFMT); ++} ++ ++static int au_iattr_test(struct au_iattr *ia, struct inode *h_inode) ++{ ++ return ia->i_ino != h_inode->i_ino ++ /* || ia->i_nlink != h_inode->i_nlink */ ++ || !uid_eq(ia->i_uid, h_inode->i_uid) ++ || !gid_eq(ia->i_gid, h_inode->i_gid) ++ || !inode_eq_iversion(h_inode, ia->i_version) ++/* ++ || ia->i_size != h_inode->i_size ++ || ia->i_blocks != h_inode->i_blocks ++*/ ++ || ia->i_mode != (h_inode->i_mode & S_IFMT); ++} ++ ++static int au_h_verify_dentry(struct dentry *h_dentry, struct dentry *h_parent, ++ struct au_branch *br) ++{ ++ int err; ++ struct au_iattr ia; ++ struct inode *h_inode; ++ struct dentry *h_d; ++ struct super_block *h_sb; ++ struct path h_ppath; ++ ++ err = 0; ++ memset(&ia, -1, sizeof(ia)); ++ h_sb = h_dentry->d_sb; ++ h_inode = NULL; ++ if (d_is_positive(h_dentry)) { ++ h_inode = d_inode(h_dentry); ++ au_iattr_save(&ia, h_inode); ++ } else if (au_test_nfs(h_sb) || au_test_fuse(h_sb)) ++ /* nfs d_revalidate may return 0 for negative dentry */ ++ /* fuse d_revalidate always return 0 for negative dentry */ ++ goto out; ++ ++ /* main purpose is namei.c:cached_lookup() and d_revalidate */ ++ h_ppath.dentry = h_parent; ++ h_ppath.mnt = au_br_mnt(br); ++ h_d = vfsub_lkup_one(&h_dentry->d_name, &h_ppath); ++ err = PTR_ERR(h_d); ++ if (IS_ERR(h_d)) ++ goto out; ++ ++ err = 0; ++ if (unlikely(h_d != h_dentry ++ || d_inode(h_d) != h_inode ++ || (h_inode && au_iattr_test(&ia, h_inode)))) ++ err = au_busy_or_stale(); ++ dput(h_d); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir, ++ struct dentry *h_parent, struct au_branch *br) ++{ ++ int err; ++ ++ err = 0; ++ if (udba == AuOpt_UDBA_REVAL ++ && !au_test_fs_remote(h_dentry->d_sb)) { ++ IMustLock(h_dir); ++ err = (d_inode(h_dentry->d_parent) != h_dir); ++ } else if (udba != AuOpt_UDBA_NONE) ++ err = au_h_verify_dentry(h_dentry, h_parent, br); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_refresh_hdentry(struct dentry *dentry, struct dentry *parent) ++{ ++ int err; ++ aufs_bindex_t new_bindex, bindex, bbot, bwh, bdiropq; ++ struct au_hdentry tmp, *p, *q; ++ struct au_dinfo *dinfo; ++ struct super_block *sb; ++ ++ DiMustWriteLock(dentry); ++ ++ sb = dentry->d_sb; ++ dinfo = au_di(dentry); ++ bbot = dinfo->di_bbot; ++ bwh = dinfo->di_bwh; ++ bdiropq = dinfo->di_bdiropq; ++ bindex = dinfo->di_btop; ++ p = au_hdentry(dinfo, bindex); ++ for (; bindex <= bbot; bindex++, p++) { ++ if (!p->hd_dentry) ++ continue; ++ ++ new_bindex = au_br_index(sb, p->hd_id); ++ if (new_bindex == bindex) ++ continue; ++ ++ if (dinfo->di_bwh == bindex) ++ bwh = new_bindex; ++ if (dinfo->di_bdiropq == bindex) ++ bdiropq = new_bindex; ++ if (new_bindex < 0) { ++ au_hdput(p); ++ p->hd_dentry = NULL; ++ continue; ++ } ++ ++ /* swap two lower dentries, and loop again */ ++ q = au_hdentry(dinfo, new_bindex); ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hd_dentry) { ++ bindex--; ++ p--; ++ } ++ } ++ ++ dinfo->di_bwh = -1; ++ if (bwh >= 0 && bwh <= au_sbbot(sb) && au_sbr_whable(sb, bwh)) ++ dinfo->di_bwh = bwh; ++ ++ dinfo->di_bdiropq = -1; ++ if (bdiropq >= 0 ++ && bdiropq <= au_sbbot(sb) ++ && au_sbr_whable(sb, bdiropq)) ++ dinfo->di_bdiropq = bdiropq; ++ ++ err = -EIO; ++ dinfo->di_btop = -1; ++ dinfo->di_bbot = -1; ++ bbot = au_dbbot(parent); ++ bindex = 0; ++ p = au_hdentry(dinfo, bindex); ++ for (; bindex <= bbot; bindex++, p++) ++ if (p->hd_dentry) { ++ dinfo->di_btop = bindex; ++ break; ++ } ++ ++ if (dinfo->di_btop >= 0) { ++ bindex = bbot; ++ p = au_hdentry(dinfo, bindex); ++ for (; bindex >= 0; bindex--, p--) ++ if (p->hd_dentry) { ++ dinfo->di_bbot = bindex; ++ err = 0; ++ break; ++ } ++ } ++ ++ return err; ++} ++ ++static void au_do_hide(struct dentry *dentry) ++{ ++ struct inode *inode; ++ ++ if (d_really_is_positive(dentry)) { ++ inode = d_inode(dentry); ++ if (!d_is_dir(dentry)) { ++ if (inode->i_nlink && !d_unhashed(dentry)) ++ drop_nlink(inode); ++ } else { ++ clear_nlink(inode); ++ /* stop next lookup */ ++ inode->i_flags |= S_DEAD; ++ } ++ smp_mb(); /* necessary? */ ++ } ++ d_drop(dentry); ++} ++ ++static int au_hide_children(struct dentry *parent) ++{ ++ int err, i, j, ndentry; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry *dentry; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, parent, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ /* in reverse order */ ++ for (i = dpages.ndpage - 1; i >= 0; i--) { ++ dpage = dpages.dpages + i; ++ ndentry = dpage->ndentry; ++ for (j = ndentry - 1; j >= 0; j--) { ++ dentry = dpage->dentries[j]; ++ if (dentry != parent) ++ au_do_hide(dentry); ++ } ++ } ++ ++out_dpages: ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++static void au_hide(struct dentry *dentry) ++{ ++ int err; ++ ++ AuDbgDentry(dentry); ++ if (d_is_dir(dentry)) { ++ /* shrink_dcache_parent(dentry); */ ++ err = au_hide_children(dentry); ++ if (unlikely(err)) ++ AuIOErr("%pd, failed hiding children, ignored %d\n", ++ dentry, err); ++ } ++ au_do_hide(dentry); ++} ++ ++/* ++ * By adding a dirty branch, a cached dentry may be affected in various ways. ++ * ++ * a dirty branch is added ++ * - on the top of layers ++ * - in the middle of layers ++ * - to the bottom of layers ++ * ++ * on the added branch there exists ++ * - a whiteout ++ * - a diropq ++ * - a same named entry ++ * + exist ++ * * negative --> positive ++ * * positive --> positive ++ * - type is unchanged ++ * - type is changed ++ * + doesn't exist ++ * * negative --> negative ++ * * positive --> negative (rejected by au_br_del() for non-dir case) ++ * - none ++ */ ++static int au_refresh_by_dinfo(struct dentry *dentry, struct au_dinfo *dinfo, ++ struct au_dinfo *tmp) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct { ++ struct dentry *dentry; ++ struct inode *inode; ++ mode_t mode; ++ } orig_h, tmp_h = { ++ .dentry = NULL ++ }; ++ struct au_hdentry *hd; ++ struct inode *inode, *h_inode; ++ struct dentry *h_dentry; ++ ++ err = 0; ++ AuDebugOn(dinfo->di_btop < 0); ++ orig_h.mode = 0; ++ orig_h.dentry = au_hdentry(dinfo, dinfo->di_btop)->hd_dentry; ++ orig_h.inode = NULL; ++ if (d_is_positive(orig_h.dentry)) { ++ orig_h.inode = d_inode(orig_h.dentry); ++ orig_h.mode = orig_h.inode->i_mode & S_IFMT; ++ } ++ if (tmp->di_btop >= 0) { ++ tmp_h.dentry = au_hdentry(tmp, tmp->di_btop)->hd_dentry; ++ if (d_is_positive(tmp_h.dentry)) { ++ tmp_h.inode = d_inode(tmp_h.dentry); ++ tmp_h.mode = tmp_h.inode->i_mode & S_IFMT; ++ } ++ } ++ ++ inode = NULL; ++ if (d_really_is_positive(dentry)) ++ inode = d_inode(dentry); ++ if (!orig_h.inode) { ++ AuDbg("negative originally\n"); ++ if (inode) { ++ au_hide(dentry); ++ goto out; ++ } ++ AuDebugOn(inode); ++ AuDebugOn(dinfo->di_btop != dinfo->di_bbot); ++ AuDebugOn(dinfo->di_bdiropq != -1); ++ ++ if (!tmp_h.inode) { ++ AuDbg("negative --> negative\n"); ++ /* should have only one negative lower */ ++ if (tmp->di_btop >= 0 ++ && tmp->di_btop < dinfo->di_btop) { ++ AuDebugOn(tmp->di_btop != tmp->di_bbot); ++ AuDebugOn(dinfo->di_btop != dinfo->di_bbot); ++ au_set_h_dptr(dentry, dinfo->di_btop, NULL); ++ au_di_cp(dinfo, tmp); ++ hd = au_hdentry(tmp, tmp->di_btop); ++ au_set_h_dptr(dentry, tmp->di_btop, ++ dget(hd->hd_dentry)); ++ } ++ au_dbg_verify_dinode(dentry); ++ } else { ++ AuDbg("negative --> positive\n"); ++ /* ++ * similar to the behaviour of creating with bypassing ++ * aufs. ++ * unhash it in order to force an error in the ++ * succeeding create operation. ++ * we should not set S_DEAD here. ++ */ ++ d_drop(dentry); ++ /* au_di_swap(tmp, dinfo); */ ++ au_dbg_verify_dinode(dentry); ++ } ++ } else { ++ AuDbg("positive originally\n"); ++ /* inode may be NULL */ ++ AuDebugOn(inode && (inode->i_mode & S_IFMT) != orig_h.mode); ++ if (!tmp_h.inode) { ++ AuDbg("positive --> negative\n"); ++ /* or bypassing aufs */ ++ au_hide(dentry); ++ if (tmp->di_bwh >= 0 && tmp->di_bwh <= dinfo->di_btop) ++ dinfo->di_bwh = tmp->di_bwh; ++ if (inode) ++ err = au_refresh_hinode_self(inode); ++ au_dbg_verify_dinode(dentry); ++ } else if (orig_h.mode == tmp_h.mode) { ++ AuDbg("positive --> positive, same type\n"); ++ if (!S_ISDIR(orig_h.mode) ++ && dinfo->di_btop > tmp->di_btop) { ++ /* ++ * similar to the behaviour of removing and ++ * creating. ++ */ ++ au_hide(dentry); ++ if (inode) ++ err = au_refresh_hinode_self(inode); ++ au_dbg_verify_dinode(dentry); ++ } else { ++ /* fill empty slots */ ++ if (dinfo->di_btop > tmp->di_btop) ++ dinfo->di_btop = tmp->di_btop; ++ if (dinfo->di_bbot < tmp->di_bbot) ++ dinfo->di_bbot = tmp->di_bbot; ++ dinfo->di_bwh = tmp->di_bwh; ++ dinfo->di_bdiropq = tmp->di_bdiropq; ++ bbot = dinfo->di_bbot; ++ bindex = tmp->di_btop; ++ hd = au_hdentry(tmp, bindex); ++ for (; bindex <= bbot; bindex++, hd++) { ++ if (au_h_dptr(dentry, bindex)) ++ continue; ++ h_dentry = hd->hd_dentry; ++ if (!h_dentry) ++ continue; ++ AuDebugOn(d_is_negative(h_dentry)); ++ h_inode = d_inode(h_dentry); ++ AuDebugOn(orig_h.mode ++ != (h_inode->i_mode ++ & S_IFMT)); ++ au_set_h_dptr(dentry, bindex, ++ dget(h_dentry)); ++ } ++ if (inode) ++ err = au_refresh_hinode(inode, dentry); ++ au_dbg_verify_dinode(dentry); ++ } ++ } else { ++ AuDbg("positive --> positive, different type\n"); ++ /* similar to the behaviour of removing and creating */ ++ au_hide(dentry); ++ if (inode) ++ err = au_refresh_hinode_self(inode); ++ au_dbg_verify_dinode(dentry); ++ } ++ } ++ ++out: ++ return err; ++} ++ ++void au_refresh_dop(struct dentry *dentry, int force_reval) ++{ ++ const struct dentry_operations *dop ++ = force_reval ? &aufs_dop : dentry->d_sb->s_d_op; ++ static const unsigned int mask ++ = DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE; ++ ++ BUILD_BUG_ON(sizeof(mask) != sizeof(dentry->d_flags)); ++ ++ if (dentry->d_op == dop) ++ return; ++ ++ AuDbg("%pd\n", dentry); ++ spin_lock(&dentry->d_lock); ++ if (dop == &aufs_dop) ++ dentry->d_flags |= mask; ++ else ++ dentry->d_flags &= ~mask; ++ dentry->d_op = dop; ++ spin_unlock(&dentry->d_lock); ++} ++ ++int au_refresh_dentry(struct dentry *dentry, struct dentry *parent) ++{ ++ int err, ebrange, nbr; ++ unsigned int sigen; ++ struct au_dinfo *dinfo, *tmp; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ DiMustWriteLock(dentry); ++ AuDebugOn(IS_ROOT(dentry)); ++ AuDebugOn(d_really_is_negative(parent)); ++ ++ sb = dentry->d_sb; ++ sigen = au_sigen(sb); ++ err = au_digen_test(parent, sigen); ++ if (unlikely(err)) ++ goto out; ++ ++ nbr = au_sbbot(sb) + 1; ++ dinfo = au_di(dentry); ++ err = au_di_realloc(dinfo, nbr, /*may_shrink*/0); ++ if (unlikely(err)) ++ goto out; ++ ebrange = au_dbrange_test(dentry); ++ if (!ebrange) ++ ebrange = au_do_refresh_hdentry(dentry, parent); ++ ++ if (d_unhashed(dentry) || ebrange /* || dinfo->di_tmpfile */) { ++ AuDebugOn(au_dbtop(dentry) < 0 && au_dbbot(dentry) >= 0); ++ if (d_really_is_positive(dentry)) { ++ inode = d_inode(dentry); ++ err = au_refresh_hinode_self(inode); ++ } ++ au_dbg_verify_dinode(dentry); ++ if (!err) ++ goto out_dgen; /* success */ ++ goto out; ++ } ++ ++ /* temporary dinfo */ ++ AuDbgDentry(dentry); ++ err = -ENOMEM; ++ tmp = au_di_alloc(sb, AuLsc_DI_TMP); ++ if (unlikely(!tmp)) ++ goto out; ++ au_di_swap(tmp, dinfo); ++ /* returns the number of positive dentries */ ++ /* ++ * if current working dir is removed, it returns an error. ++ * but the dentry is legal. ++ */ ++ err = au_lkup_dentry(dentry, /*btop*/0, AuLkup_ALLOW_NEG); ++ AuDbgDentry(dentry); ++ au_di_swap(tmp, dinfo); ++ if (err == -ENOENT) ++ err = 0; ++ if (err >= 0) { ++ /* compare/refresh by dinfo */ ++ AuDbgDentry(dentry); ++ err = au_refresh_by_dinfo(dentry, dinfo, tmp); ++ au_dbg_verify_dinode(dentry); ++ AuTraceErr(err); ++ } ++ au_di_realloc(dinfo, nbr, /*may_shrink*/1); /* harmless if err */ ++ au_rw_write_unlock(&tmp->di_rwsem); ++ au_di_free(tmp); ++ if (unlikely(err)) ++ goto out; ++ ++out_dgen: ++ au_update_digen(dentry); ++out: ++ if (unlikely(err && !(dentry->d_flags & DCACHE_NFSFS_RENAMED))) { ++ AuIOErr("failed refreshing %pd, %d\n", dentry, err); ++ AuDbgDentry(dentry); ++ } ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_do_h_d_reval(struct dentry *h_dentry, unsigned int flags, ++ struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ int err, valid; ++ ++ err = 0; ++ if (!(h_dentry->d_flags & DCACHE_OP_REVALIDATE)) ++ goto out; ++ ++ AuDbg("b%d\n", bindex); ++ /* ++ * gave up supporting LOOKUP_CREATE/OPEN for lower fs, ++ * due to whiteout and branch permission. ++ */ ++ flags &= ~(/*LOOKUP_PARENT |*/ LOOKUP_OPEN | LOOKUP_CREATE ++ | LOOKUP_FOLLOW | LOOKUP_EXCL); ++ /* it may return tri-state */ ++ valid = h_dentry->d_op->d_revalidate(h_dentry, flags); ++ ++ if (unlikely(valid < 0)) ++ err = valid; ++ else if (!valid) ++ err = -EINVAL; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* todo: remove this */ ++static int h_d_revalidate(struct dentry *dentry, struct inode *inode, ++ unsigned int flags, int do_udba, int dirren) ++{ ++ int err; ++ umode_t mode, h_mode; ++ aufs_bindex_t bindex, btail, btop, ibs, ibe; ++ unsigned char plus, unhashed, is_root, h_plus, h_nfs, tmpfile; ++ struct inode *h_inode, *h_cached_inode; ++ struct dentry *h_dentry; ++ struct qstr *name, *h_name; ++ ++ err = 0; ++ plus = 0; ++ mode = 0; ++ ibs = -1; ++ ibe = -1; ++ unhashed = !!d_unhashed(dentry); ++ is_root = !!IS_ROOT(dentry); ++ name = &dentry->d_name; ++ tmpfile = au_di(dentry)->di_tmpfile; ++ ++ /* ++ * Theoretically, REVAL test should be unnecessary in case of ++ * {FS,I}NOTIFY. ++ * But {fs,i}notify doesn't fire some necessary events, ++ * IN_ATTRIB for atime/nlink/pageio ++ * Let's do REVAL test too. ++ */ ++ if (do_udba && inode) { ++ mode = (inode->i_mode & S_IFMT); ++ plus = (inode->i_nlink > 0); ++ ibs = au_ibtop(inode); ++ ibe = au_ibbot(inode); ++ } ++ ++ btop = au_dbtop(dentry); ++ btail = btop; ++ if (inode && S_ISDIR(inode->i_mode)) ++ btail = au_dbtaildir(dentry); ++ for (bindex = btop; bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ ++ AuDbg("b%d, %pd\n", bindex, h_dentry); ++ h_nfs = !!au_test_nfs(h_dentry->d_sb); ++ spin_lock(&h_dentry->d_lock); ++ h_name = &h_dentry->d_name; ++ if (unlikely(do_udba ++ && !is_root ++ && ((!h_nfs ++ && (unhashed != !!d_unhashed(h_dentry) ++ || (!tmpfile && !dirren ++ && !au_qstreq(name, h_name)) ++ )) ++ || (h_nfs ++ && !(flags & LOOKUP_OPEN) ++ && (h_dentry->d_flags ++ & DCACHE_NFSFS_RENAMED))) ++ )) { ++ int h_unhashed; ++ ++ h_unhashed = d_unhashed(h_dentry); ++ spin_unlock(&h_dentry->d_lock); ++ AuDbg("unhash 0x%x 0x%x, %pd %pd\n", ++ unhashed, h_unhashed, dentry, h_dentry); ++ goto err; ++ } ++ spin_unlock(&h_dentry->d_lock); ++ ++ err = au_do_h_d_reval(h_dentry, flags, dentry, bindex); ++ if (unlikely(err)) ++ /* do not goto err, to keep the errno */ ++ break; ++ ++ /* todo: plink too? */ ++ if (!do_udba) ++ continue; ++ ++ /* UDBA tests */ ++ if (unlikely(!!inode != d_is_positive(h_dentry))) ++ goto err; ++ ++ h_inode = NULL; ++ if (d_is_positive(h_dentry)) ++ h_inode = d_inode(h_dentry); ++ h_plus = plus; ++ h_mode = mode; ++ h_cached_inode = h_inode; ++ if (h_inode) { ++ h_mode = (h_inode->i_mode & S_IFMT); ++ h_plus = (h_inode->i_nlink > 0); ++ } ++ if (inode && ibs <= bindex && bindex <= ibe) ++ h_cached_inode = au_h_iptr(inode, bindex); ++ ++ if (!h_nfs) { ++ if (unlikely(plus != h_plus && !tmpfile)) ++ goto err; ++ } else { ++ if (unlikely(!(h_dentry->d_flags & DCACHE_NFSFS_RENAMED) ++ && !is_root ++ && !IS_ROOT(h_dentry) ++ && unhashed != d_unhashed(h_dentry))) ++ goto err; ++ } ++ if (unlikely(mode != h_mode ++ || h_cached_inode != h_inode)) ++ goto err; ++ continue; ++ ++err: ++ err = -EINVAL; ++ break; ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* todo: consolidate with do_refresh() and au_reval_for_attr() */ ++static int simple_reval_dpath(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ struct dentry *parent; ++ ++ if (!au_digen_test(dentry, sigen)) ++ return 0; ++ ++ parent = dget_parent(dentry); ++ di_read_lock_parent(parent, AuLock_IR); ++ AuDebugOn(au_digen_test(parent, sigen)); ++ au_dbg_verify_gen(parent, sigen); ++ err = au_refresh_dentry(dentry, parent); ++ di_read_unlock(parent, AuLock_IR); ++ dput(parent); ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_reval_dpath(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ struct dentry *d, *parent; ++ ++ if (!au_ftest_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR)) ++ return simple_reval_dpath(dentry, sigen); ++ ++ /* slow loop, keep it simple and stupid */ ++ /* cf: au_cpup_dirs() */ ++ err = 0; ++ parent = NULL; ++ while (au_digen_test(dentry, sigen)) { ++ d = dentry; ++ while (1) { ++ dput(parent); ++ parent = dget_parent(d); ++ if (!au_digen_test(parent, sigen)) ++ break; ++ d = parent; ++ } ++ ++ if (d != dentry) ++ di_write_lock_child2(d); ++ ++ /* someone might update our dentry while we were sleeping */ ++ if (au_digen_test(d, sigen)) { ++ /* ++ * todo: consolidate with simple_reval_dpath(), ++ * do_refresh() and au_reval_for_attr(). ++ */ ++ di_read_lock_parent(parent, AuLock_IR); ++ err = au_refresh_dentry(d, parent); ++ di_read_unlock(parent, AuLock_IR); ++ } ++ ++ if (d != dentry) ++ di_write_unlock(d); ++ dput(parent); ++ if (unlikely(err)) ++ break; ++ } ++ ++ return err; ++} ++ ++/* ++ * if valid returns 1, otherwise 0. ++ */ ++static int aufs_d_revalidate(struct dentry *dentry, unsigned int flags) ++{ ++ int valid, err; ++ unsigned int sigen; ++ unsigned char do_udba, dirren; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ /* todo: support rcu-walk? */ ++ if (flags & LOOKUP_RCU) ++ return -ECHILD; ++ ++ valid = 0; ++ if (unlikely(!au_di(dentry))) ++ goto out; ++ ++ valid = 1; ++ sb = dentry->d_sb; ++ /* ++ * todo: very ugly ++ * i_mutex of parent dir may be held, ++ * but we should not return 'invalid' due to busy. ++ */ ++ err = aufs_read_lock(dentry, AuLock_FLUSH | AuLock_DW | AuLock_NOPLM); ++ if (unlikely(err)) { ++ valid = err; ++ AuTraceErr(err); ++ goto out; ++ } ++ inode = NULL; ++ if (d_really_is_positive(dentry)) ++ inode = d_inode(dentry); ++ if (unlikely(inode && au_is_bad_inode(inode))) { ++ err = -EINVAL; ++ AuTraceErr(err); ++ goto out_dgrade; ++ } ++ if (unlikely(au_dbrange_test(dentry))) { ++ err = -EINVAL; ++ AuTraceErr(err); ++ goto out_dgrade; ++ } ++ ++ sigen = au_sigen(sb); ++ if (au_digen_test(dentry, sigen)) { ++ AuDebugOn(IS_ROOT(dentry)); ++ err = au_reval_dpath(dentry, sigen); ++ if (unlikely(err)) { ++ AuTraceErr(err); ++ goto out_dgrade; ++ } ++ } ++ di_downgrade_lock(dentry, AuLock_IR); ++ ++ err = -EINVAL; ++ if (!(flags & (LOOKUP_OPEN | LOOKUP_EMPTY)) ++ && inode ++ && !(inode->i_state && I_LINKABLE) ++ && (IS_DEADDIR(inode) || !inode->i_nlink)) { ++ AuTraceErr(err); ++ goto out_inval; ++ } ++ ++ do_udba = !au_opt_test(au_mntflags(sb), UDBA_NONE); ++ if (do_udba && inode) { ++ aufs_bindex_t btop = au_ibtop(inode); ++ struct inode *h_inode; ++ ++ if (btop >= 0) { ++ h_inode = au_h_iptr(inode, btop); ++ if (h_inode && au_test_higen(inode, h_inode)) { ++ AuTraceErr(err); ++ goto out_inval; ++ } ++ } ++ } ++ ++ dirren = !!au_opt_test(au_mntflags(sb), DIRREN); ++ err = h_d_revalidate(dentry, inode, flags, do_udba, dirren); ++ if (unlikely(!err && do_udba && au_dbtop(dentry) < 0)) { ++ err = -EIO; ++ AuDbg("both of real entry and whiteout found, %p, err %d\n", ++ dentry, err); ++ } ++ goto out_inval; ++ ++out_dgrade: ++ di_downgrade_lock(dentry, AuLock_IR); ++out_inval: ++ aufs_read_unlock(dentry, AuLock_IR); ++ AuTraceErr(err); ++ valid = !err; ++out: ++ if (!valid) { ++ AuDbg("%pd invalid, %d\n", dentry, valid); ++ d_drop(dentry); ++ } ++ return valid; ++} ++ ++static void aufs_d_release(struct dentry *dentry) ++{ ++ if (au_di(dentry)) { ++ au_di_fin(dentry); ++ au_hn_di_reinit(dentry); ++ } ++} ++ ++const struct dentry_operations aufs_dop = { ++ .d_revalidate = aufs_d_revalidate, ++ .d_weak_revalidate = aufs_d_revalidate, ++ .d_release = aufs_d_release ++}; ++ ++/* aufs_dop without d_revalidate */ ++const struct dentry_operations aufs_dop_noreval = { ++ .d_release = aufs_d_release ++}; +diff -Naur null/fs/aufs/dentry.h linux-5.15.36/fs/aufs/dentry.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/dentry.h 2022-05-10 16:51:39.868744219 +0300 +@@ -0,0 +1,269 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * lookup and dentry operations ++ */ ++ ++#ifndef __AUFS_DENTRY_H__ ++#define __AUFS_DENTRY_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "dirren.h" ++#include "rwsem.h" ++ ++struct au_hdentry { ++ struct dentry *hd_dentry; ++ aufs_bindex_t hd_id; ++}; ++ ++struct au_dinfo { ++ atomic_t di_generation; ++ ++ struct au_rwsem di_rwsem; ++ aufs_bindex_t di_btop, di_bbot, di_bwh, di_bdiropq; ++ unsigned char di_tmpfile; /* to allow the different name */ ++ struct au_hdentry *di_hdentry; ++ struct rcu_head rcu; ++} ____cacheline_aligned_in_smp; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* flags for au_lkup_dentry() */ ++#define AuLkup_ALLOW_NEG 1 ++#define AuLkup_IGNORE_PERM (1 << 1) ++#define AuLkup_DIRREN (1 << 2) ++#define au_ftest_lkup(flags, name) ((flags) & AuLkup_##name) ++#define au_fset_lkup(flags, name) \ ++ do { (flags) |= AuLkup_##name; } while (0) ++#define au_fclr_lkup(flags, name) \ ++ do { (flags) &= ~AuLkup_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_DIRREN ++#undef AuLkup_DIRREN ++#define AuLkup_DIRREN 0 ++#endif ++ ++struct au_do_lookup_args { ++ unsigned int flags; ++ mode_t type; ++ struct qstr whname, *name; ++ struct au_dr_lookup dirren; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dentry.c */ ++extern const struct dentry_operations aufs_dop, aufs_dop_noreval; ++struct au_branch; ++struct dentry *au_sio_lkup_one(struct user_namespace *userns, struct qstr *name, ++ struct path *ppath); ++int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir, ++ struct dentry *h_parent, struct au_branch *br); ++ ++int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t btop, ++ unsigned int flags); ++int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex, int wh); ++int au_refresh_dentry(struct dentry *dentry, struct dentry *parent); ++int au_reval_dpath(struct dentry *dentry, unsigned int sigen); ++void au_refresh_dop(struct dentry *dentry, int force_reval); ++ ++/* dinfo.c */ ++void au_di_init_once(void *_di); ++struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc); ++void au_di_free(struct au_dinfo *dinfo); ++void au_di_swap(struct au_dinfo *a, struct au_dinfo *b); ++void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src); ++int au_di_init(struct dentry *dentry); ++void au_di_fin(struct dentry *dentry); ++int au_di_realloc(struct au_dinfo *dinfo, int nbr, int may_shrink); ++ ++void di_read_lock(struct dentry *d, int flags, unsigned int lsc); ++void di_read_unlock(struct dentry *d, int flags); ++void di_downgrade_lock(struct dentry *d, int flags); ++void di_write_lock(struct dentry *d, unsigned int lsc); ++void di_write_unlock(struct dentry *d); ++void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir); ++void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir); ++void di_write_unlock2(struct dentry *d1, struct dentry *d2); ++ ++struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex); ++struct dentry *au_h_d_alias(struct dentry *dentry, aufs_bindex_t bindex); ++aufs_bindex_t au_dbtail(struct dentry *dentry); ++aufs_bindex_t au_dbtaildir(struct dentry *dentry); ++ ++void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_dentry); ++int au_digen_test(struct dentry *dentry, unsigned int sigen); ++int au_dbrange_test(struct dentry *dentry); ++void au_update_digen(struct dentry *dentry); ++void au_update_dbrange(struct dentry *dentry, int do_put_zero); ++void au_update_dbtop(struct dentry *dentry); ++void au_update_dbbot(struct dentry *dentry); ++int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_dinfo *au_di(struct dentry *dentry) ++{ ++ return dentry->d_fsdata; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock subclass for dinfo */ ++enum { ++ AuLsc_DI_CHILD, /* child first */ ++ AuLsc_DI_CHILD2, /* rename(2), link(2), and cpup at hnotify */ ++ AuLsc_DI_CHILD3, /* copyup dirs */ ++ AuLsc_DI_PARENT, ++ AuLsc_DI_PARENT2, ++ AuLsc_DI_PARENT3, ++ AuLsc_DI_TMP /* temp for replacing dinfo */ ++}; ++ ++/* ++ * di_read_lock_child, di_write_lock_child, ++ * di_read_lock_child2, di_write_lock_child2, ++ * di_read_lock_child3, di_write_lock_child3, ++ * di_read_lock_parent, di_write_lock_parent, ++ * di_read_lock_parent2, di_write_lock_parent2, ++ * di_read_lock_parent3, di_write_lock_parent3, ++ */ ++#define AuReadLockFunc(name, lsc) \ ++static inline void di_read_lock_##name(struct dentry *d, int flags) \ ++{ di_read_lock(d, flags, AuLsc_DI_##lsc); } ++ ++#define AuWriteLockFunc(name, lsc) \ ++static inline void di_write_lock_##name(struct dentry *d) \ ++{ di_write_lock(d, AuLsc_DI_##lsc); } ++ ++#define AuRWLockFuncs(name, lsc) \ ++ AuReadLockFunc(name, lsc) \ ++ AuWriteLockFunc(name, lsc) ++ ++AuRWLockFuncs(child, CHILD); ++AuRWLockFuncs(child2, CHILD2); ++AuRWLockFuncs(child3, CHILD3); ++AuRWLockFuncs(parent, PARENT); ++AuRWLockFuncs(parent2, PARENT2); ++AuRWLockFuncs(parent3, PARENT3); ++ ++#undef AuReadLockFunc ++#undef AuWriteLockFunc ++#undef AuRWLockFuncs ++ ++#define DiMustNoWaiters(d) AuRwMustNoWaiters(&au_di(d)->di_rwsem) ++#define DiMustAnyLock(d) AuRwMustAnyLock(&au_di(d)->di_rwsem) ++#define DiMustWriteLock(d) AuRwMustWriteLock(&au_di(d)->di_rwsem) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* todo: memory barrier? */ ++static inline unsigned int au_digen(struct dentry *d) ++{ ++ return atomic_read(&au_di(d)->di_generation); ++} ++ ++static inline void au_h_dentry_init(struct au_hdentry *hdentry) ++{ ++ hdentry->hd_dentry = NULL; ++} ++ ++static inline struct au_hdentry *au_hdentry(struct au_dinfo *di, ++ aufs_bindex_t bindex) ++{ ++ return di->di_hdentry + bindex; ++} ++ ++static inline void au_hdput(struct au_hdentry *hd) ++{ ++ if (hd) ++ dput(hd->hd_dentry); ++} ++ ++static inline aufs_bindex_t au_dbtop(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_btop; ++} ++ ++static inline aufs_bindex_t au_dbbot(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_bbot; ++} ++ ++static inline aufs_bindex_t au_dbwh(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_bwh; ++} ++ ++static inline aufs_bindex_t au_dbdiropq(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_bdiropq; ++} ++ ++/* todo: hard/soft set? */ ++static inline void au_set_dbtop(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ au_di(dentry)->di_btop = bindex; ++} ++ ++static inline void au_set_dbbot(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ au_di(dentry)->di_bbot = bindex; ++} ++ ++static inline void au_set_dbwh(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ /* dbwh can be outside of btop - bbot range */ ++ au_di(dentry)->di_bwh = bindex; ++} ++ ++static inline void au_set_dbdiropq(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ au_di(dentry)->di_bdiropq = bindex; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_HNOTIFY ++static inline void au_digen_dec(struct dentry *d) ++{ ++ atomic_dec(&au_di(d)->di_generation); ++} ++ ++static inline void au_hn_di_reinit(struct dentry *dentry) ++{ ++ dentry->d_fsdata = NULL; ++} ++#else ++AuStubVoid(au_hn_di_reinit, struct dentry *dentry __maybe_unused) ++#endif /* CONFIG_AUFS_HNOTIFY */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DENTRY_H__ */ +diff -Naur null/fs/aufs/dinfo.c linux-5.15.36/fs/aufs/dinfo.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/dinfo.c 2022-05-10 16:51:39.869744219 +0300 +@@ -0,0 +1,554 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * dentry private data ++ */ ++ ++#include "aufs.h" ++ ++void au_di_init_once(void *_dinfo) ++{ ++ struct au_dinfo *dinfo = _dinfo; ++ ++ au_rw_init(&dinfo->di_rwsem); ++} ++ ++struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc) ++{ ++ struct au_dinfo *dinfo; ++ int nbr, i; ++ ++ dinfo = au_cache_alloc_dinfo(); ++ if (unlikely(!dinfo)) ++ goto out; ++ ++ nbr = au_sbbot(sb) + 1; ++ if (nbr <= 0) ++ nbr = 1; ++ dinfo->di_hdentry = kcalloc(nbr, sizeof(*dinfo->di_hdentry), GFP_NOFS); ++ if (dinfo->di_hdentry) { ++ au_rw_write_lock_nested(&dinfo->di_rwsem, lsc); ++ dinfo->di_btop = -1; ++ dinfo->di_bbot = -1; ++ dinfo->di_bwh = -1; ++ dinfo->di_bdiropq = -1; ++ dinfo->di_tmpfile = 0; ++ for (i = 0; i < nbr; i++) ++ dinfo->di_hdentry[i].hd_id = -1; ++ goto out; ++ } ++ ++ au_cache_free_dinfo(dinfo); ++ dinfo = NULL; ++ ++out: ++ return dinfo; ++} ++ ++void au_di_free(struct au_dinfo *dinfo) ++{ ++ struct au_hdentry *p; ++ aufs_bindex_t bbot, bindex; ++ ++ /* dentry may not be revalidated */ ++ bindex = dinfo->di_btop; ++ if (bindex >= 0) { ++ bbot = dinfo->di_bbot; ++ p = au_hdentry(dinfo, bindex); ++ while (bindex++ <= bbot) ++ au_hdput(p++); ++ } ++ au_kfree_try_rcu(dinfo->di_hdentry); ++ au_cache_free_dinfo(dinfo); ++} ++ ++void au_di_swap(struct au_dinfo *a, struct au_dinfo *b) ++{ ++ struct au_hdentry *p; ++ aufs_bindex_t bi; ++ ++ AuRwMustWriteLock(&a->di_rwsem); ++ AuRwMustWriteLock(&b->di_rwsem); ++ ++#define DiSwap(v, name) \ ++ do { \ ++ v = a->di_##name; \ ++ a->di_##name = b->di_##name; \ ++ b->di_##name = v; \ ++ } while (0) ++ ++ DiSwap(p, hdentry); ++ DiSwap(bi, btop); ++ DiSwap(bi, bbot); ++ DiSwap(bi, bwh); ++ DiSwap(bi, bdiropq); ++ /* smp_mb(); */ ++ ++#undef DiSwap ++} ++ ++void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src) ++{ ++ AuRwMustWriteLock(&dst->di_rwsem); ++ AuRwMustWriteLock(&src->di_rwsem); ++ ++ dst->di_btop = src->di_btop; ++ dst->di_bbot = src->di_bbot; ++ dst->di_bwh = src->di_bwh; ++ dst->di_bdiropq = src->di_bdiropq; ++ /* smp_mb(); */ ++} ++ ++int au_di_init(struct dentry *dentry) ++{ ++ int err; ++ struct super_block *sb; ++ struct au_dinfo *dinfo; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ dinfo = au_di_alloc(sb, AuLsc_DI_CHILD); ++ if (dinfo) { ++ atomic_set(&dinfo->di_generation, au_sigen(sb)); ++ /* smp_mb(); */ /* atomic_set */ ++ dentry->d_fsdata = dinfo; ++ } else ++ err = -ENOMEM; ++ ++ return err; ++} ++ ++void au_di_fin(struct dentry *dentry) ++{ ++ struct au_dinfo *dinfo; ++ ++ dinfo = au_di(dentry); ++ AuRwDestroy(&dinfo->di_rwsem); ++ au_di_free(dinfo); ++} ++ ++int au_di_realloc(struct au_dinfo *dinfo, int nbr, int may_shrink) ++{ ++ int err, sz; ++ struct au_hdentry *hdp; ++ ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ err = -ENOMEM; ++ sz = sizeof(*hdp) * (dinfo->di_bbot + 1); ++ if (!sz) ++ sz = sizeof(*hdp); ++ hdp = au_kzrealloc(dinfo->di_hdentry, sz, sizeof(*hdp) * nbr, GFP_NOFS, ++ may_shrink); ++ if (hdp) { ++ dinfo->di_hdentry = hdp; ++ err = 0; ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void do_ii_write_lock(struct inode *inode, unsigned int lsc) ++{ ++ switch (lsc) { ++ case AuLsc_DI_CHILD: ++ ii_write_lock_child(inode); ++ break; ++ case AuLsc_DI_CHILD2: ++ ii_write_lock_child2(inode); ++ break; ++ case AuLsc_DI_CHILD3: ++ ii_write_lock_child3(inode); ++ break; ++ case AuLsc_DI_PARENT: ++ ii_write_lock_parent(inode); ++ break; ++ case AuLsc_DI_PARENT2: ++ ii_write_lock_parent2(inode); ++ break; ++ case AuLsc_DI_PARENT3: ++ ii_write_lock_parent3(inode); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++static void do_ii_read_lock(struct inode *inode, unsigned int lsc) ++{ ++ switch (lsc) { ++ case AuLsc_DI_CHILD: ++ ii_read_lock_child(inode); ++ break; ++ case AuLsc_DI_CHILD2: ++ ii_read_lock_child2(inode); ++ break; ++ case AuLsc_DI_CHILD3: ++ ii_read_lock_child3(inode); ++ break; ++ case AuLsc_DI_PARENT: ++ ii_read_lock_parent(inode); ++ break; ++ case AuLsc_DI_PARENT2: ++ ii_read_lock_parent2(inode); ++ break; ++ case AuLsc_DI_PARENT3: ++ ii_read_lock_parent3(inode); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++void di_read_lock(struct dentry *d, int flags, unsigned int lsc) ++{ ++ struct inode *inode; ++ ++ au_rw_read_lock_nested(&au_di(d)->di_rwsem, lsc); ++ if (d_really_is_positive(d)) { ++ inode = d_inode(d); ++ if (au_ftest_lock(flags, IW)) ++ do_ii_write_lock(inode, lsc); ++ else if (au_ftest_lock(flags, IR)) ++ do_ii_read_lock(inode, lsc); ++ } ++} ++ ++void di_read_unlock(struct dentry *d, int flags) ++{ ++ struct inode *inode; ++ ++ if (d_really_is_positive(d)) { ++ inode = d_inode(d); ++ if (au_ftest_lock(flags, IW)) { ++ au_dbg_verify_dinode(d); ++ ii_write_unlock(inode); ++ } else if (au_ftest_lock(flags, IR)) { ++ au_dbg_verify_dinode(d); ++ ii_read_unlock(inode); ++ } ++ } ++ au_rw_read_unlock(&au_di(d)->di_rwsem); ++} ++ ++void di_downgrade_lock(struct dentry *d, int flags) ++{ ++ if (d_really_is_positive(d) && au_ftest_lock(flags, IR)) ++ ii_downgrade_lock(d_inode(d)); ++ au_rw_dgrade_lock(&au_di(d)->di_rwsem); ++} ++ ++void di_write_lock(struct dentry *d, unsigned int lsc) ++{ ++ au_rw_write_lock_nested(&au_di(d)->di_rwsem, lsc); ++ if (d_really_is_positive(d)) ++ do_ii_write_lock(d_inode(d), lsc); ++} ++ ++void di_write_unlock(struct dentry *d) ++{ ++ au_dbg_verify_dinode(d); ++ if (d_really_is_positive(d)) ++ ii_write_unlock(d_inode(d)); ++ au_rw_write_unlock(&au_di(d)->di_rwsem); ++} ++ ++void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir) ++{ ++ AuDebugOn(d1 == d2 ++ || d_inode(d1) == d_inode(d2) ++ || d1->d_sb != d2->d_sb); ++ ++ if ((isdir && au_test_subdir(d1, d2)) ++ || d1 < d2) { ++ di_write_lock_child(d1); ++ di_write_lock_child2(d2); ++ } else { ++ di_write_lock_child(d2); ++ di_write_lock_child2(d1); ++ } ++} ++ ++void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir) ++{ ++ AuDebugOn(d1 == d2 ++ || d_inode(d1) == d_inode(d2) ++ || d1->d_sb != d2->d_sb); ++ ++ if ((isdir && au_test_subdir(d1, d2)) ++ || d1 < d2) { ++ di_write_lock_parent(d1); ++ di_write_lock_parent2(d2); ++ } else { ++ di_write_lock_parent(d2); ++ di_write_lock_parent2(d1); ++ } ++} ++ ++void di_write_unlock2(struct dentry *d1, struct dentry *d2) ++{ ++ di_write_unlock(d1); ++ if (d_inode(d1) == d_inode(d2)) ++ au_rw_write_unlock(&au_di(d2)->di_rwsem); ++ else ++ di_write_unlock(d2); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ struct dentry *d; ++ ++ DiMustAnyLock(dentry); ++ ++ if (au_dbtop(dentry) < 0 || bindex < au_dbtop(dentry)) ++ return NULL; ++ AuDebugOn(bindex < 0); ++ d = au_hdentry(au_di(dentry), bindex)->hd_dentry; ++ AuDebugOn(d && au_dcount(d) <= 0); ++ return d; ++} ++ ++/* ++ * extended version of au_h_dptr(). ++ * returns a hashed and positive (or linkable) h_dentry in bindex, NULL, or ++ * error. ++ */ ++struct dentry *au_h_d_alias(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ struct dentry *h_dentry; ++ struct inode *inode, *h_inode; ++ ++ AuDebugOn(d_really_is_negative(dentry)); ++ ++ h_dentry = NULL; ++ if (au_dbtop(dentry) <= bindex ++ && bindex <= au_dbbot(dentry)) ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && !au_d_linkable(h_dentry)) { ++ dget(h_dentry); ++ goto out; /* success */ ++ } ++ ++ inode = d_inode(dentry); ++ AuDebugOn(bindex < au_ibtop(inode)); ++ AuDebugOn(au_ibbot(inode) < bindex); ++ h_inode = au_h_iptr(inode, bindex); ++ h_dentry = d_find_alias(h_inode); ++ if (h_dentry) { ++ if (!IS_ERR(h_dentry)) { ++ if (!au_d_linkable(h_dentry)) ++ goto out; /* success */ ++ dput(h_dentry); ++ } else ++ goto out; ++ } ++ ++ if (au_opt_test(au_mntflags(dentry->d_sb), PLINK)) { ++ h_dentry = au_plink_lkup(inode, bindex); ++ AuDebugOn(!h_dentry); ++ if (!IS_ERR(h_dentry)) { ++ if (!au_d_hashed_positive(h_dentry)) ++ goto out; /* success */ ++ dput(h_dentry); ++ h_dentry = NULL; ++ } ++ } ++ ++out: ++ AuDbgDentry(h_dentry); ++ return h_dentry; ++} ++ ++aufs_bindex_t au_dbtail(struct dentry *dentry) ++{ ++ aufs_bindex_t bbot, bwh; ++ ++ bbot = au_dbbot(dentry); ++ if (0 <= bbot) { ++ bwh = au_dbwh(dentry); ++ if (!bwh) ++ return bwh; ++ if (0 < bwh && bwh < bbot) ++ return bwh - 1; ++ } ++ return bbot; ++} ++ ++aufs_bindex_t au_dbtaildir(struct dentry *dentry) ++{ ++ aufs_bindex_t bbot, bopq; ++ ++ bbot = au_dbtail(dentry); ++ if (0 <= bbot) { ++ bopq = au_dbdiropq(dentry); ++ if (0 <= bopq && bopq < bbot) ++ bbot = bopq; ++ } ++ return bbot; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_dentry) ++{ ++ struct au_dinfo *dinfo; ++ struct au_hdentry *hd; ++ struct au_branch *br; ++ ++ DiMustWriteLock(dentry); ++ ++ dinfo = au_di(dentry); ++ hd = au_hdentry(dinfo, bindex); ++ au_hdput(hd); ++ hd->hd_dentry = h_dentry; ++ if (h_dentry) { ++ br = au_sbr(dentry->d_sb, bindex); ++ hd->hd_id = br->br_id; ++ } ++} ++ ++int au_dbrange_test(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t btop, bbot; ++ ++ err = 0; ++ btop = au_dbtop(dentry); ++ bbot = au_dbbot(dentry); ++ if (btop >= 0) ++ AuDebugOn(bbot < 0 && btop > bbot); ++ else { ++ err = -EIO; ++ AuDebugOn(bbot >= 0); ++ } ++ ++ return err; ++} ++ ++int au_digen_test(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ ++ err = 0; ++ if (unlikely(au_digen(dentry) != sigen ++ || au_iigen_test(d_inode(dentry), sigen))) ++ err = -EIO; ++ ++ return err; ++} ++ ++void au_update_digen(struct dentry *dentry) ++{ ++ atomic_set(&au_di(dentry)->di_generation, au_sigen(dentry->d_sb)); ++ /* smp_mb(); */ /* atomic_set */ ++} ++ ++void au_update_dbrange(struct dentry *dentry, int do_put_zero) ++{ ++ struct au_dinfo *dinfo; ++ struct dentry *h_d; ++ struct au_hdentry *hdp; ++ aufs_bindex_t bindex, bbot; ++ ++ DiMustWriteLock(dentry); ++ ++ dinfo = au_di(dentry); ++ if (!dinfo || dinfo->di_btop < 0) ++ return; ++ ++ if (do_put_zero) { ++ bbot = dinfo->di_bbot; ++ bindex = dinfo->di_btop; ++ hdp = au_hdentry(dinfo, bindex); ++ for (; bindex <= bbot; bindex++, hdp++) { ++ h_d = hdp->hd_dentry; ++ if (h_d && d_is_negative(h_d)) ++ au_set_h_dptr(dentry, bindex, NULL); ++ } ++ } ++ ++ dinfo->di_btop = 0; ++ hdp = au_hdentry(dinfo, dinfo->di_btop); ++ for (; dinfo->di_btop <= dinfo->di_bbot; dinfo->di_btop++, hdp++) ++ if (hdp->hd_dentry) ++ break; ++ if (dinfo->di_btop > dinfo->di_bbot) { ++ dinfo->di_btop = -1; ++ dinfo->di_bbot = -1; ++ return; ++ } ++ ++ hdp = au_hdentry(dinfo, dinfo->di_bbot); ++ for (; dinfo->di_bbot >= 0; dinfo->di_bbot--, hdp--) ++ if (hdp->hd_dentry) ++ break; ++ AuDebugOn(dinfo->di_btop > dinfo->di_bbot || dinfo->di_bbot < 0); ++} ++ ++void au_update_dbtop(struct dentry *dentry) ++{ ++ aufs_bindex_t bindex, bbot; ++ struct dentry *h_dentry; ++ ++ bbot = au_dbbot(dentry); ++ for (bindex = au_dbtop(dentry); bindex <= bbot; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ if (d_is_positive(h_dentry)) { ++ au_set_dbtop(dentry, bindex); ++ return; ++ } ++ au_set_h_dptr(dentry, bindex, NULL); ++ } ++} ++ ++void au_update_dbbot(struct dentry *dentry) ++{ ++ aufs_bindex_t bindex, btop; ++ struct dentry *h_dentry; ++ ++ btop = au_dbtop(dentry); ++ for (bindex = au_dbbot(dentry); bindex >= btop; bindex--) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ if (d_is_positive(h_dentry)) { ++ au_set_dbbot(dentry, bindex); ++ return; ++ } ++ au_set_h_dptr(dentry, bindex, NULL); ++ } ++} ++ ++int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry) ++{ ++ aufs_bindex_t bindex, bbot; ++ ++ bbot = au_dbbot(dentry); ++ for (bindex = au_dbtop(dentry); bindex <= bbot; bindex++) ++ if (au_h_dptr(dentry, bindex) == h_dentry) ++ return bindex; ++ return -1; ++} +diff -Naur null/fs/aufs/dir.c linux-5.15.36/fs/aufs/dir.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/dir.c 2022-05-10 16:51:39.869744219 +0300 +@@ -0,0 +1,765 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * directory operations ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++void au_add_nlink(struct inode *dir, struct inode *h_dir) ++{ ++ unsigned int nlink; ++ ++ AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode)); ++ ++ nlink = dir->i_nlink; ++ nlink += h_dir->i_nlink - 2; ++ if (h_dir->i_nlink < 2) ++ nlink += 2; ++ smp_mb(); /* for i_nlink */ ++ /* 0 can happen in revaliding */ ++ set_nlink(dir, nlink); ++} ++ ++void au_sub_nlink(struct inode *dir, struct inode *h_dir) ++{ ++ unsigned int nlink; ++ ++ AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode)); ++ ++ nlink = dir->i_nlink; ++ nlink -= h_dir->i_nlink - 2; ++ if (h_dir->i_nlink < 2) ++ nlink -= 2; ++ smp_mb(); /* for i_nlink */ ++ /* nlink == 0 means the branch-fs is broken */ ++ set_nlink(dir, nlink); ++} ++ ++loff_t au_dir_size(struct file *file, struct dentry *dentry) ++{ ++ loff_t sz; ++ aufs_bindex_t bindex, bbot; ++ struct file *h_file; ++ struct dentry *h_dentry; ++ ++ sz = 0; ++ if (file) { ++ AuDebugOn(!d_is_dir(file->f_path.dentry)); ++ ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); ++ bindex <= bbot && sz < KMALLOC_MAX_SIZE; ++ bindex++) { ++ h_file = au_hf_dir(file, bindex); ++ if (h_file && file_inode(h_file)) ++ sz += vfsub_f_size_read(h_file); ++ } ++ } else { ++ AuDebugOn(!dentry); ++ AuDebugOn(!d_is_dir(dentry)); ++ ++ bbot = au_dbtaildir(dentry); ++ for (bindex = au_dbtop(dentry); ++ bindex <= bbot && sz < KMALLOC_MAX_SIZE; ++ bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && d_is_positive(h_dentry)) ++ sz += i_size_read(d_inode(h_dentry)); ++ } ++ } ++ if (sz < KMALLOC_MAX_SIZE) ++ sz = roundup_pow_of_two(sz); ++ if (sz > KMALLOC_MAX_SIZE) ++ sz = KMALLOC_MAX_SIZE; ++ else if (sz < NAME_MAX) { ++ BUILD_BUG_ON(AUFS_RDBLK_DEF < NAME_MAX); ++ sz = AUFS_RDBLK_DEF; ++ } ++ return sz; ++} ++ ++struct au_dir_ts_arg { ++ struct dentry *dentry; ++ aufs_bindex_t brid; ++}; ++ ++static void au_do_dir_ts(void *arg) ++{ ++ struct au_dir_ts_arg *a = arg; ++ struct au_dtime dt; ++ struct path h_path; ++ struct inode *dir, *h_dir; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_hinode *hdir; ++ int err; ++ aufs_bindex_t btop, bindex; ++ ++ sb = a->dentry->d_sb; ++ if (d_really_is_negative(a->dentry)) ++ goto out; ++ /* no dir->i_mutex lock */ ++ aufs_read_lock(a->dentry, AuLock_DW); /* noflush */ ++ ++ dir = d_inode(a->dentry); ++ btop = au_ibtop(dir); ++ bindex = au_br_index(sb, a->brid); ++ if (bindex < btop) ++ goto out_unlock; ++ ++ br = au_sbr(sb, bindex); ++ h_path.dentry = au_h_dptr(a->dentry, bindex); ++ if (!h_path.dentry) ++ goto out_unlock; ++ h_path.mnt = au_br_mnt(br); ++ au_dtime_store(&dt, a->dentry, &h_path); ++ ++ br = au_sbr(sb, btop); ++ if (!au_br_writable(br->br_perm)) ++ goto out_unlock; ++ h_path.dentry = au_h_dptr(a->dentry, btop); ++ h_path.mnt = au_br_mnt(br); ++ err = vfsub_mnt_want_write(h_path.mnt); ++ if (err) ++ goto out_unlock; ++ hdir = au_hi(dir, btop); ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ h_dir = au_h_iptr(dir, btop); ++ if (h_dir->i_nlink ++ && timespec64_compare(&h_dir->i_mtime, &dt.dt_mtime) < 0) { ++ dt.dt_h_path = h_path; ++ au_dtime_revert(&dt); ++ } ++ au_hn_inode_unlock(hdir); ++ vfsub_mnt_drop_write(h_path.mnt); ++ au_cpup_attr_timesizes(dir); ++ ++out_unlock: ++ aufs_read_unlock(a->dentry, AuLock_DW); ++out: ++ dput(a->dentry); ++ au_nwt_done(&au_sbi(sb)->si_nowait); ++ au_kfree_try_rcu(arg); ++} ++ ++void au_dir_ts(struct inode *dir, aufs_bindex_t bindex) ++{ ++ int perm, wkq_err; ++ aufs_bindex_t btop; ++ struct au_dir_ts_arg *arg; ++ struct dentry *dentry; ++ struct super_block *sb; ++ ++ IMustLock(dir); ++ ++ dentry = d_find_any_alias(dir); ++ AuDebugOn(!dentry); ++ sb = dentry->d_sb; ++ btop = au_ibtop(dir); ++ if (btop == bindex) { ++ au_cpup_attr_timesizes(dir); ++ goto out; ++ } ++ ++ perm = au_sbr_perm(sb, btop); ++ if (!au_br_writable(perm)) ++ goto out; ++ ++ arg = kmalloc(sizeof(*arg), GFP_NOFS); ++ if (!arg) ++ goto out; ++ ++ arg->dentry = dget(dentry); /* will be dput-ted by au_do_dir_ts() */ ++ arg->brid = au_sbr_id(sb, bindex); ++ wkq_err = au_wkq_nowait(au_do_dir_ts, arg, sb, /*flags*/0); ++ if (unlikely(wkq_err)) { ++ pr_err("wkq %d\n", wkq_err); ++ dput(dentry); ++ au_kfree_try_rcu(arg); ++ } ++ ++out: ++ dput(dentry); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int reopen_dir(struct file *file) ++{ ++ int err; ++ unsigned int flags; ++ aufs_bindex_t bindex, btail, btop; ++ struct dentry *dentry, *h_dentry; ++ struct file *h_file; ++ ++ /* open all lower dirs */ ++ dentry = file->f_path.dentry; ++ btop = au_dbtop(dentry); ++ for (bindex = au_fbtop(file); bindex < btop; bindex++) ++ au_set_h_fptr(file, bindex, NULL); ++ au_set_fbtop(file, btop); ++ ++ btail = au_dbtaildir(dentry); ++ for (bindex = au_fbbot_dir(file); btail < bindex; bindex--) ++ au_set_h_fptr(file, bindex, NULL); ++ au_set_fbbot_dir(file, btail); ++ ++ flags = vfsub_file_flags(file); ++ for (bindex = btop; bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ h_file = au_hf_dir(file, bindex); ++ if (h_file) ++ continue; ++ ++ h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; /* close all? */ ++ au_set_h_fptr(file, bindex, h_file); ++ } ++ au_update_figen(file); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ err = 0; ++ ++out: ++ return err; ++} ++ ++static int do_open_dir(struct file *file, int flags, struct file *h_file) ++{ ++ int err; ++ aufs_bindex_t bindex, btail; ++ struct dentry *dentry, *h_dentry; ++ struct vfsmount *mnt; ++ ++ FiMustWriteLock(file); ++ AuDebugOn(h_file); ++ ++ err = 0; ++ mnt = file->f_path.mnt; ++ dentry = file->f_path.dentry; ++ file->f_version = inode_query_iversion(d_inode(dentry)); ++ bindex = au_dbtop(dentry); ++ au_set_fbtop(file, bindex); ++ btail = au_dbtaildir(dentry); ++ au_set_fbbot_dir(file, btail); ++ for (; !err && bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ ++ err = vfsub_test_mntns(mnt, h_dentry->d_sb); ++ if (unlikely(err)) ++ break; ++ h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0); ++ if (IS_ERR(h_file)) { ++ err = PTR_ERR(h_file); ++ break; ++ } ++ au_set_h_fptr(file, bindex, h_file); ++ } ++ au_update_figen(file); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ if (!err) ++ return 0; /* success */ ++ ++ /* close all */ ++ for (bindex = au_fbtop(file); bindex <= btail; bindex++) ++ au_set_h_fptr(file, bindex, NULL); ++ au_set_fbtop(file, -1); ++ au_set_fbbot_dir(file, -1); ++ ++ return err; ++} ++ ++static int aufs_open_dir(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ int err; ++ struct super_block *sb; ++ struct au_fidir *fidir; ++ ++ err = -ENOMEM; ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ fidir = au_fidir_alloc(sb); ++ if (fidir) { ++ struct au_do_open_args args = { ++ .open = do_open_dir, ++ .fidir = fidir ++ }; ++ err = au_do_open(file, &args); ++ if (unlikely(err)) ++ au_kfree_rcu(fidir); ++ } ++ si_read_unlock(sb); ++ return err; ++} ++ ++static int aufs_release_dir(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ struct au_vdir *vdir_cache; ++ struct au_finfo *finfo; ++ struct au_fidir *fidir; ++ struct au_hfile *hf; ++ aufs_bindex_t bindex, bbot; ++ ++ finfo = au_fi(file); ++ fidir = finfo->fi_hdir; ++ if (fidir) { ++ au_hbl_del(&finfo->fi_hlist, ++ &au_sbi(file->f_path.dentry->d_sb)->si_files); ++ vdir_cache = fidir->fd_vdir_cache; /* lock-free */ ++ if (vdir_cache) ++ au_vdir_free(vdir_cache); ++ ++ bindex = finfo->fi_btop; ++ if (bindex >= 0) { ++ hf = fidir->fd_hfile + bindex; ++ /* ++ * calls fput() instead of filp_close(), ++ * since no dnotify or lock for the lower file. ++ */ ++ bbot = fidir->fd_bbot; ++ for (; bindex <= bbot; bindex++, hf++) ++ if (hf->hf_file) ++ au_hfput(hf, /*execed*/0); ++ } ++ au_kfree_rcu(fidir); ++ finfo->fi_hdir = NULL; ++ } ++ au_finfo_fin(file); ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_flush_dir(struct file *file, fl_owner_t id) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct file *h_file; ++ ++ err = 0; ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); !err && bindex <= bbot; bindex++) { ++ h_file = au_hf_dir(file, bindex); ++ if (h_file) ++ err = vfsub_flush(h_file, id); ++ } ++ return err; ++} ++ ++static int aufs_flush_dir(struct file *file, fl_owner_t id) ++{ ++ return au_do_flush(file, id, au_do_flush_dir); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_fsync_dir_no_file(struct dentry *dentry, int datasync) ++{ ++ int err; ++ aufs_bindex_t bbot, bindex; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ bbot = au_dbbot(dentry); ++ for (bindex = au_dbtop(dentry); !err && bindex <= bbot; bindex++) { ++ struct path h_path; ++ ++ if (au_test_ro(sb, bindex, inode)) ++ continue; ++ h_path.dentry = au_h_dptr(dentry, bindex); ++ if (!h_path.dentry) ++ continue; ++ ++ h_path.mnt = au_sbr_mnt(sb, bindex); ++ err = vfsub_fsync(NULL, &h_path, datasync); ++ } ++ ++ return err; ++} ++ ++static int au_do_fsync_dir(struct file *file, int datasync) ++{ ++ int err; ++ aufs_bindex_t bbot, bindex; ++ struct file *h_file; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1, /*fi_lsc*/0); ++ if (unlikely(err)) ++ goto out; ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); !err && bindex <= bbot; bindex++) { ++ h_file = au_hf_dir(file, bindex); ++ if (!h_file || au_test_ro(sb, bindex, inode)) ++ continue; ++ ++ err = vfsub_fsync(h_file, &h_file->f_path, datasync); ++ } ++ ++out: ++ return err; ++} ++ ++/* ++ * @file may be NULL ++ */ ++static int aufs_fsync_dir(struct file *file, loff_t start, loff_t end, ++ int datasync) ++{ ++ int err; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ err = 0; ++ dentry = file->f_path.dentry; ++ inode = d_inode(dentry); ++ inode_lock(inode); ++ sb = dentry->d_sb; ++ si_noflush_read_lock(sb); ++ if (file) ++ err = au_do_fsync_dir(file, datasync); ++ else { ++ di_write_lock_child(dentry); ++ err = au_do_fsync_dir_no_file(dentry, datasync); ++ } ++ au_cpup_attr_timesizes(inode); ++ di_write_unlock(dentry); ++ if (file) ++ fi_write_unlock(file); ++ ++ si_read_unlock(sb); ++ inode_unlock(inode); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_iterate_shared(struct file *file, struct dir_context *ctx) ++{ ++ int err; ++ struct dentry *dentry; ++ struct inode *inode, *h_inode; ++ struct super_block *sb; ++ ++ AuDbg("%pD, ctx{%ps, %llu}\n", file, ctx->actor, ctx->pos); ++ ++ dentry = file->f_path.dentry; ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ ++ sb = dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1, /*fi_lsc*/0); ++ if (unlikely(err)) ++ goto out; ++ err = au_alive_dir(dentry); ++ if (!err) ++ err = au_vdir_init(file); ++ di_downgrade_lock(dentry, AuLock_IR); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ h_inode = au_h_iptr(inode, au_ibtop(inode)); ++ if (!au_test_nfsd()) { ++ err = au_vdir_fill_de(file, ctx); ++ fsstack_copy_attr_atime(inode, h_inode); ++ } else { ++ /* ++ * nfsd filldir may call lookup_one_len(), vfs_getattr(), ++ * encode_fh() and others. ++ */ ++ atomic_inc(&h_inode->i_count); ++ di_read_unlock(dentry, AuLock_IR); ++ si_read_unlock(sb); ++ err = au_vdir_fill_de(file, ctx); ++ fsstack_copy_attr_atime(inode, h_inode); ++ fi_write_unlock(file); ++ iput(h_inode); ++ ++ AuTraceErr(err); ++ return err; ++ } ++ ++out_unlock: ++ di_read_unlock(dentry, AuLock_IR); ++ fi_write_unlock(file); ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define AuTestEmpty_WHONLY 1 ++#define AuTestEmpty_CALLED (1 << 1) ++#define AuTestEmpty_SHWH (1 << 2) ++#define au_ftest_testempty(flags, name) ((flags) & AuTestEmpty_##name) ++#define au_fset_testempty(flags, name) \ ++ do { (flags) |= AuTestEmpty_##name; } while (0) ++#define au_fclr_testempty(flags, name) \ ++ do { (flags) &= ~AuTestEmpty_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_SHWH ++#undef AuTestEmpty_SHWH ++#define AuTestEmpty_SHWH 0 ++#endif ++ ++struct test_empty_arg { ++ struct dir_context ctx; ++ struct au_nhash *whlist; ++ unsigned int flags; ++ int err; ++ aufs_bindex_t bindex; ++}; ++ ++static int test_empty_cb(struct dir_context *ctx, const char *__name, ++ int namelen, loff_t offset __maybe_unused, u64 ino, ++ unsigned int d_type) ++{ ++ struct test_empty_arg *arg = container_of(ctx, struct test_empty_arg, ++ ctx); ++ char *name = (void *)__name; ++ ++ arg->err = 0; ++ au_fset_testempty(arg->flags, CALLED); ++ /* smp_mb(); */ ++ if (name[0] == '.' ++ && (namelen == 1 || (name[1] == '.' && namelen == 2))) ++ goto out; /* success */ ++ ++ if (namelen <= AUFS_WH_PFX_LEN ++ || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { ++ if (au_ftest_testempty(arg->flags, WHONLY) ++ && !au_nhash_test_known_wh(arg->whlist, name, namelen)) ++ arg->err = -ENOTEMPTY; ++ goto out; ++ } ++ ++ name += AUFS_WH_PFX_LEN; ++ namelen -= AUFS_WH_PFX_LEN; ++ if (!au_nhash_test_known_wh(arg->whlist, name, namelen)) ++ arg->err = au_nhash_append_wh ++ (arg->whlist, name, namelen, ino, d_type, arg->bindex, ++ au_ftest_testempty(arg->flags, SHWH)); ++ ++out: ++ /* smp_mb(); */ ++ AuTraceErr(arg->err); ++ return arg->err; ++} ++ ++static int do_test_empty(struct dentry *dentry, struct test_empty_arg *arg) ++{ ++ int err; ++ struct file *h_file; ++ struct au_branch *br; ++ ++ h_file = au_h_open(dentry, arg->bindex, ++ O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_LARGEFILE, ++ /*file*/NULL, /*force_wr*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = 0; ++ if (!au_opt_test(au_mntflags(dentry->d_sb), UDBA_NONE) ++ && !file_inode(h_file)->i_nlink) ++ goto out_put; ++ ++ do { ++ arg->err = 0; ++ au_fclr_testempty(arg->flags, CALLED); ++ /* smp_mb(); */ ++ err = vfsub_iterate_dir(h_file, &arg->ctx); ++ if (err >= 0) ++ err = arg->err; ++ } while (!err && au_ftest_testempty(arg->flags, CALLED)); ++ ++out_put: ++ fput(h_file); ++ br = au_sbr(dentry->d_sb, arg->bindex); ++ au_lcnt_dec(&br->br_nfiles); ++out: ++ return err; ++} ++ ++struct do_test_empty_args { ++ int *errp; ++ struct dentry *dentry; ++ struct test_empty_arg *arg; ++}; ++ ++static void call_do_test_empty(void *args) ++{ ++ struct do_test_empty_args *a = args; ++ *a->errp = do_test_empty(a->dentry, a->arg); ++} ++ ++static int sio_test_empty(struct dentry *dentry, struct test_empty_arg *arg) ++{ ++ int err, wkq_err; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct user_namespace *h_userns; ++ ++ h_userns = au_sbr_userns(dentry->d_sb, arg->bindex); ++ h_dentry = au_h_dptr(dentry, arg->bindex); ++ h_inode = d_inode(h_dentry); ++ /* todo: i_mode changes anytime? */ ++ inode_lock_shared_nested(h_inode, AuLsc_I_CHILD); ++ err = au_test_h_perm_sio(h_userns, h_inode, MAY_EXEC | MAY_READ); ++ inode_unlock_shared(h_inode); ++ if (!err) ++ err = do_test_empty(dentry, arg); ++ else { ++ struct do_test_empty_args args = { ++ .errp = &err, ++ .dentry = dentry, ++ .arg = arg ++ }; ++ unsigned int flags = arg->flags; ++ ++ wkq_err = au_wkq_wait(call_do_test_empty, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ arg->flags = flags; ++ } ++ ++ return err; ++} ++ ++int au_test_empty_lower(struct dentry *dentry) ++{ ++ int err; ++ unsigned int rdhash; ++ aufs_bindex_t bindex, btop, btail; ++ struct au_nhash whlist; ++ struct test_empty_arg arg = { ++ .ctx = { ++ .actor = test_empty_cb ++ } ++ }; ++ int (*test_empty)(struct dentry *dentry, struct test_empty_arg *arg); ++ ++ SiMustAnyLock(dentry->d_sb); ++ ++ rdhash = au_sbi(dentry->d_sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, dentry)); ++ err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ ++ arg.flags = 0; ++ arg.whlist = &whlist; ++ btop = au_dbtop(dentry); ++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)) ++ au_fset_testempty(arg.flags, SHWH); ++ test_empty = do_test_empty; ++ if (au_opt_test(au_mntflags(dentry->d_sb), DIRPERM1)) ++ test_empty = sio_test_empty; ++ arg.bindex = btop; ++ err = test_empty(dentry, &arg); ++ if (unlikely(err)) ++ goto out_whlist; ++ ++ au_fset_testempty(arg.flags, WHONLY); ++ btail = au_dbtaildir(dentry); ++ for (bindex = btop + 1; !err && bindex <= btail; bindex++) { ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && d_is_positive(h_dentry)) { ++ arg.bindex = bindex; ++ err = test_empty(dentry, &arg); ++ } ++ } ++ ++out_whlist: ++ au_nhash_wh_free(&whlist); ++out: ++ return err; ++} ++ ++int au_test_empty(struct dentry *dentry, struct au_nhash *whlist) ++{ ++ int err; ++ struct test_empty_arg arg = { ++ .ctx = { ++ .actor = test_empty_cb ++ } ++ }; ++ aufs_bindex_t bindex, btail; ++ ++ err = 0; ++ arg.whlist = whlist; ++ arg.flags = AuTestEmpty_WHONLY; ++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)) ++ au_fset_testempty(arg.flags, SHWH); ++ btail = au_dbtaildir(dentry); ++ for (bindex = au_dbtop(dentry); !err && bindex <= btail; bindex++) { ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && d_is_positive(h_dentry)) { ++ arg.bindex = bindex; ++ err = sio_test_empty(dentry, &arg); ++ } ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++const struct file_operations aufs_dir_fop = { ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++ .read = generic_read_dir, ++ .iterate_shared = aufs_iterate_shared, ++ .unlocked_ioctl = aufs_ioctl_dir, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = aufs_compat_ioctl_dir, ++#endif ++ .open = aufs_open_dir, ++ .release = aufs_release_dir, ++ .flush = aufs_flush_dir, ++ .fsync = aufs_fsync_dir ++}; +diff -Naur null/fs/aufs/dir.h linux-5.15.36/fs/aufs/dir.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/dir.h 2022-05-10 16:51:39.869744219 +0300 +@@ -0,0 +1,134 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * directory operations ++ */ ++ ++#ifndef __AUFS_DIR_H__ ++#define __AUFS_DIR_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* need to be faster and smaller */ ++ ++struct au_nhash { ++ unsigned int nh_num; ++ struct hlist_head *nh_head; ++}; ++ ++struct au_vdir_destr { ++ unsigned char len; ++ unsigned char name[]; ++} __packed; ++ ++struct au_vdir_dehstr { ++ struct hlist_node hash; ++ struct au_vdir_destr *str; ++ struct rcu_head rcu; ++} ____cacheline_aligned_in_smp; ++ ++struct au_vdir_de { ++ ino_t de_ino; ++ unsigned char de_type; ++ /* caution: packed */ ++ struct au_vdir_destr de_str; ++} __packed; ++ ++struct au_vdir_wh { ++ struct hlist_node wh_hash; ++#ifdef CONFIG_AUFS_SHWH ++ ino_t wh_ino; ++ aufs_bindex_t wh_bindex; ++ unsigned char wh_type; ++#else ++ aufs_bindex_t wh_bindex; ++#endif ++ /* caution: packed */ ++ struct au_vdir_destr wh_str; ++} __packed; ++ ++union au_vdir_deblk_p { ++ unsigned char *deblk; ++ struct au_vdir_de *de; ++}; ++ ++struct au_vdir { ++ unsigned char **vd_deblk; ++ unsigned long vd_nblk; ++ struct { ++ unsigned long ul; ++ union au_vdir_deblk_p p; ++ } vd_last; ++ ++ u64 vd_version; ++ unsigned int vd_deblk_sz; ++ unsigned long vd_jiffy; ++ struct rcu_head rcu; ++} ____cacheline_aligned_in_smp; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dir.c */ ++extern const struct file_operations aufs_dir_fop; ++void au_add_nlink(struct inode *dir, struct inode *h_dir); ++void au_sub_nlink(struct inode *dir, struct inode *h_dir); ++loff_t au_dir_size(struct file *file, struct dentry *dentry); ++void au_dir_ts(struct inode *dir, aufs_bindex_t bsrc); ++int au_test_empty_lower(struct dentry *dentry); ++int au_test_empty(struct dentry *dentry, struct au_nhash *whlist); ++ ++/* vdir.c */ ++unsigned int au_rdhash_est(loff_t sz); ++int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp); ++void au_nhash_wh_free(struct au_nhash *whlist); ++int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt, ++ int limit); ++int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen); ++int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino, ++ unsigned int d_type, aufs_bindex_t bindex, ++ unsigned char shwh); ++void au_vdir_free(struct au_vdir *vdir); ++int au_vdir_init(struct file *file); ++int au_vdir_fill_de(struct file *file, struct dir_context *ctx); ++ ++/* ioctl.c */ ++long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg); ++ ++#ifdef CONFIG_AUFS_RDU ++/* rdu.c */ ++long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg); ++#ifdef CONFIG_COMPAT ++long au_rdu_compat_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg); ++#endif ++#else ++AuStub(long, au_rdu_ioctl, return -EINVAL, struct file *file, ++ unsigned int cmd, unsigned long arg) ++#ifdef CONFIG_COMPAT ++AuStub(long, au_rdu_compat_ioctl, return -EINVAL, struct file *file, ++ unsigned int cmd, unsigned long arg) ++#endif ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DIR_H__ */ +diff -Naur null/fs/aufs/dirren.c linux-5.15.36/fs/aufs/dirren.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/dirren.c 2022-05-10 16:51:39.869744219 +0300 +@@ -0,0 +1,1315 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2017-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * special handling in renaming a directory ++ * in order to support looking-up the before-renamed name on the lower readonly ++ * branches ++ */ ++ ++#include ++#include "aufs.h" ++ ++static void au_dr_hino_del(struct au_dr_br *dr, struct au_dr_hino *ent) ++{ ++ int idx; ++ ++ idx = au_dr_ihash(ent->dr_h_ino); ++ au_hbl_del(&ent->dr_hnode, dr->dr_h_ino + idx); ++} ++ ++static int au_dr_hino_test_empty(struct au_dr_br *dr) ++{ ++ int ret, i; ++ struct hlist_bl_head *hbl; ++ ++ ret = 1; ++ for (i = 0; ret && i < AuDirren_NHASH; i++) { ++ hbl = dr->dr_h_ino + i; ++ hlist_bl_lock(hbl); ++ ret &= hlist_bl_empty(hbl); ++ hlist_bl_unlock(hbl); ++ } ++ ++ return ret; ++} ++ ++static struct au_dr_hino *au_dr_hino_find(struct au_dr_br *dr, ino_t ino) ++{ ++ struct au_dr_hino *found, *ent; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ int idx; ++ ++ found = NULL; ++ idx = au_dr_ihash(ino); ++ hbl = dr->dr_h_ino + idx; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(ent, pos, hbl, dr_hnode) ++ if (ent->dr_h_ino == ino) { ++ found = ent; ++ break; ++ } ++ hlist_bl_unlock(hbl); ++ ++ return found; ++} ++ ++int au_dr_hino_test_add(struct au_dr_br *dr, ino_t ino, ++ struct au_dr_hino *add_ent) ++{ ++ int found, idx; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_dr_hino *ent; ++ ++ found = 0; ++ idx = au_dr_ihash(ino); ++ hbl = dr->dr_h_ino + idx; ++#if 0 /* debug print */ ++ { ++ struct hlist_bl_node *tmp; ++ ++ hlist_bl_for_each_entry_safe(ent, pos, tmp, hbl, dr_hnode) ++ AuDbg("hi%llu\n", (unsigned long long)ent->dr_h_ino); ++ } ++#endif ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(ent, pos, hbl, dr_hnode) ++ if (ent->dr_h_ino == ino) { ++ found = 1; ++ break; ++ } ++ if (!found && add_ent) ++ hlist_bl_add_head(&add_ent->dr_hnode, hbl); ++ hlist_bl_unlock(hbl); ++ ++ if (!found && add_ent) ++ AuDbg("i%llu added\n", (unsigned long long)add_ent->dr_h_ino); ++ ++ return found; ++} ++ ++void au_dr_hino_free(struct au_dr_br *dr) ++{ ++ int i; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos, *tmp; ++ struct au_dr_hino *ent; ++ ++ /* SiMustWriteLock(sb); */ ++ ++ for (i = 0; i < AuDirren_NHASH; i++) { ++ hbl = dr->dr_h_ino + i; ++ /* no spinlock since sbinfo must be write-locked */ ++ hlist_bl_for_each_entry_safe(ent, pos, tmp, hbl, dr_hnode) ++ au_kfree_rcu(ent); ++ INIT_HLIST_BL_HEAD(hbl); ++ } ++} ++ ++/* returns the number of inodes or an error */ ++static int au_dr_hino_store(struct super_block *sb, struct au_branch *br, ++ struct file *hinofile) ++{ ++ int err, i; ++ ssize_t ssz; ++ loff_t pos, oldsize; ++ __be64 u64; ++ struct inode *hinoinode; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *n1, *n2; ++ struct au_dr_hino *ent; ++ ++ SiMustWriteLock(sb); ++ AuDebugOn(!au_br_writable(br->br_perm)); ++ ++ hinoinode = file_inode(hinofile); ++ oldsize = i_size_read(hinoinode); ++ ++ err = 0; ++ pos = 0; ++ hbl = br->br_dirren.dr_h_ino; ++ for (i = 0; !err && i < AuDirren_NHASH; i++, hbl++) { ++ /* no bit-lock since sbinfo must be write-locked */ ++ hlist_bl_for_each_entry_safe(ent, n1, n2, hbl, dr_hnode) { ++ AuDbg("hi%llu, %pD2\n", ++ (unsigned long long)ent->dr_h_ino, hinofile); ++ u64 = cpu_to_be64(ent->dr_h_ino); ++ ssz = vfsub_write_k(hinofile, &u64, sizeof(u64), &pos); ++ if (ssz == sizeof(u64)) ++ continue; ++ ++ /* write error */ ++ pr_err("ssz %zd, %pD2\n", ssz, hinofile); ++ err = -ENOSPC; ++ if (ssz < 0) ++ err = ssz; ++ break; ++ } ++ } ++ /* regardless the error */ ++ if (pos < oldsize) { ++ err = vfsub_trunc(&hinofile->f_path, pos, /*attr*/0, hinofile); ++ AuTraceErr(err); ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_dr_hino_load(struct au_dr_br *dr, struct file *hinofile) ++{ ++ int err, hidx; ++ ssize_t ssz; ++ size_t sz, n; ++ loff_t pos; ++ uint64_t u64; ++ struct au_dr_hino *ent; ++ struct inode *hinoinode; ++ struct hlist_bl_head *hbl; ++ ++ err = 0; ++ pos = 0; ++ hbl = dr->dr_h_ino; ++ hinoinode = file_inode(hinofile); ++ sz = i_size_read(hinoinode); ++ AuDebugOn(sz % sizeof(u64)); ++ n = sz / sizeof(u64); ++ while (n--) { ++ ssz = vfsub_read_k(hinofile, &u64, sizeof(u64), &pos); ++ if (unlikely(ssz != sizeof(u64))) { ++ pr_err("ssz %zd, %pD2\n", ssz, hinofile); ++ err = -EINVAL; ++ if (ssz < 0) ++ err = ssz; ++ goto out_free; ++ } ++ ++ ent = kmalloc(sizeof(*ent), GFP_NOFS); ++ if (!ent) { ++ err = -ENOMEM; ++ AuTraceErr(err); ++ goto out_free; ++ } ++ ent->dr_h_ino = be64_to_cpu((__force __be64)u64); ++ AuDbg("hi%llu, %pD2\n", ++ (unsigned long long)ent->dr_h_ino, hinofile); ++ hidx = au_dr_ihash(ent->dr_h_ino); ++ au_hbl_add(&ent->dr_hnode, hbl + hidx); ++ } ++ goto out; /* success */ ++ ++out_free: ++ au_dr_hino_free(dr); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * @bindex/@br is a switch to distinguish whether suspending hnotify or not. ++ * @path is a switch to distinguish load and store. ++ */ ++static int au_dr_hino(struct super_block *sb, aufs_bindex_t bindex, ++ struct au_branch *br, const struct path *path) ++{ ++ int err, flags; ++ unsigned char load, suspend; ++ struct file *hinofile; ++ struct au_hinode *hdir; ++ struct inode *dir, *delegated; ++ struct path hinopath; ++ struct qstr hinoname = QSTR_INIT(AUFS_WH_DR_BRHINO, ++ sizeof(AUFS_WH_DR_BRHINO) - 1); ++ ++ AuDebugOn(bindex < 0 && !br); ++ AuDebugOn(bindex >= 0 && br); ++ ++ err = -EINVAL; ++ suspend = !br; ++ if (suspend) ++ br = au_sbr(sb, bindex); ++ load = !!path; ++ if (!load) { ++ path = &br->br_path; ++ AuDebugOn(!au_br_writable(br->br_perm)); ++ if (unlikely(!au_br_writable(br->br_perm))) ++ goto out; ++ } ++ ++ hdir = NULL; ++ if (suspend) { ++ dir = d_inode(sb->s_root); ++ hdir = au_hinode(au_ii(dir), bindex); ++ dir = hdir->hi_inode; ++ au_hn_inode_lock_nested(hdir, AuLsc_I_CHILD); ++ } else { ++ dir = d_inode(path->dentry); ++ inode_lock_nested(dir, AuLsc_I_CHILD); ++ } ++ hinopath.mnt = path->mnt; ++ hinopath.dentry = vfsub_lkup_one(&hinoname, (struct path *)path); ++ err = PTR_ERR(hinopath.dentry); ++ if (IS_ERR(hinopath.dentry)) ++ goto out_unlock; ++ ++ err = 0; ++ flags = O_RDONLY; ++ if (load) { ++ if (d_is_negative(hinopath.dentry)) ++ goto out_dput; /* success */ ++ } else { ++ if (au_dr_hino_test_empty(&br->br_dirren)) { ++ if (d_is_positive(hinopath.dentry)) { ++ delegated = NULL; ++ err = vfsub_unlink(dir, &hinopath, &delegated, ++ /*force*/0); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ pr_err("ignored err %d, %pd2\n", ++ err, hinopath.dentry); ++ if (unlikely(err == -EWOULDBLOCK)) ++ iput(delegated); ++ err = 0; ++ } ++ goto out_dput; ++ } else if (!d_is_positive(hinopath.dentry)) { ++ err = vfsub_create(dir, &hinopath, 0600, ++ /*want_excl*/false); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out_dput; ++ } ++ flags = O_WRONLY; ++ } ++ hinofile = vfsub_dentry_open(&hinopath, flags); ++ if (suspend) ++ au_hn_inode_unlock(hdir); ++ else ++ inode_unlock(dir); ++ dput(hinopath.dentry); ++ AuTraceErrPtr(hinofile); ++ if (IS_ERR(hinofile)) { ++ err = PTR_ERR(hinofile); ++ goto out; ++ } ++ ++ if (load) ++ err = au_dr_hino_load(&br->br_dirren, hinofile); ++ else ++ err = au_dr_hino_store(sb, br, hinofile); ++ fput(hinofile); ++ goto out; ++ ++out_dput: ++ dput(hinopath.dentry); ++out_unlock: ++ if (suspend) ++ au_hn_inode_unlock(hdir); ++ else ++ inode_unlock(dir); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_dr_brid_init(struct au_dr_brid *brid, const struct path *path) ++{ ++ int err; ++ struct kstatfs kstfs; ++ dev_t dev; ++ struct dentry *dentry; ++ struct super_block *sb; ++ ++ err = vfs_statfs((void *)path, &kstfs); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out; ++ ++ /* todo: support for UUID */ ++ ++ if (kstfs.f_fsid.val[0] || kstfs.f_fsid.val[1]) { ++ brid->type = AuBrid_FSID; ++ brid->fsid = kstfs.f_fsid; ++ } else { ++ dentry = path->dentry; ++ sb = dentry->d_sb; ++ dev = sb->s_dev; ++ if (dev) { ++ brid->type = AuBrid_DEV; ++ brid->dev = dev; ++ } ++ } ++ ++out: ++ return err; ++} ++ ++int au_dr_br_init(struct super_block *sb, struct au_branch *br, ++ const struct path *path) ++{ ++ int err, i; ++ struct au_dr_br *dr; ++ struct hlist_bl_head *hbl; ++ ++ dr = &br->br_dirren; ++ hbl = dr->dr_h_ino; ++ for (i = 0; i < AuDirren_NHASH; i++, hbl++) ++ INIT_HLIST_BL_HEAD(hbl); ++ ++ err = au_dr_brid_init(&dr->dr_brid, path); ++ if (unlikely(err)) ++ goto out; ++ ++ if (au_opt_test(au_mntflags(sb), DIRREN)) ++ err = au_dr_hino(sb, /*bindex*/-1, br, path); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_dr_br_fin(struct super_block *sb, struct au_branch *br) ++{ ++ int err; ++ ++ err = 0; ++ if (au_br_writable(br->br_perm)) ++ err = au_dr_hino(sb, /*bindex*/-1, br, /*path*/NULL); ++ if (!err) ++ au_dr_hino_free(&br->br_dirren); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_brid_str(struct au_dr_brid *brid, struct inode *h_inode, ++ char *buf, size_t sz) ++{ ++ int err; ++ unsigned int major, minor; ++ char *p; ++ ++ p = buf; ++ err = snprintf(p, sz, "%d_", brid->type); ++ AuDebugOn(err > sz); ++ p += err; ++ sz -= err; ++ switch (brid->type) { ++ case AuBrid_Unset: ++ return -EINVAL; ++ case AuBrid_UUID: ++ err = snprintf(p, sz, "%pU", brid->uuid.b); ++ break; ++ case AuBrid_FSID: ++ err = snprintf(p, sz, "%08x-%08x", ++ brid->fsid.val[0], brid->fsid.val[1]); ++ break; ++ case AuBrid_DEV: ++ major = MAJOR(brid->dev); ++ minor = MINOR(brid->dev); ++ if (major <= 0xff && minor <= 0xff) ++ err = snprintf(p, sz, "%02x%02x", major, minor); ++ else ++ err = snprintf(p, sz, "%03x:%05x", major, minor); ++ break; ++ } ++ AuDebugOn(err > sz); ++ p += err; ++ sz -= err; ++ err = snprintf(p, sz, "_%llu", (unsigned long long)h_inode->i_ino); ++ AuDebugOn(err > sz); ++ p += err; ++ sz -= err; ++ ++ return p - buf; ++} ++ ++static int au_drinfo_name(struct au_branch *br, char *name, int len) ++{ ++ int rlen; ++ struct dentry *br_dentry; ++ struct inode *br_inode; ++ ++ br_dentry = au_br_dentry(br); ++ br_inode = d_inode(br_dentry); ++ rlen = au_brid_str(&br->br_dirren.dr_brid, br_inode, name, len); ++ AuDebugOn(rlen >= AUFS_DIRREN_ENV_VAL_SZ); ++ AuDebugOn(rlen > len); ++ ++ return rlen; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * from the given @h_dentry, construct drinfo at @*fdata. ++ * when the size of @*fdata is not enough, reallocate and return new @fdata and ++ * @allocated. ++ */ ++static int au_drinfo_construct(struct au_drinfo_fdata **fdata, ++ struct dentry *h_dentry, ++ unsigned char *allocated) ++{ ++ int err, v; ++ struct au_drinfo_fdata *f, *p; ++ struct au_drinfo *drinfo; ++ struct inode *h_inode; ++ struct qstr *qname; ++ ++ err = 0; ++ f = *fdata; ++ h_inode = d_inode(h_dentry); ++ qname = &h_dentry->d_name; ++ drinfo = &f->drinfo; ++ drinfo->ino = (__force uint64_t)cpu_to_be64(h_inode->i_ino); ++ drinfo->oldnamelen = qname->len; ++ if (*allocated < sizeof(*f) + qname->len) { ++ v = roundup_pow_of_two(*allocated + qname->len); ++ p = au_krealloc(f, v, GFP_NOFS, /*may_shrink*/0); ++ if (unlikely(!p)) { ++ err = -ENOMEM; ++ AuTraceErr(err); ++ goto out; ++ } ++ f = p; ++ *fdata = f; ++ *allocated = v; ++ drinfo = &f->drinfo; ++ } ++ memcpy(drinfo->oldname, qname->name, qname->len); ++ AuDbg("i%llu, %.*s\n", ++ be64_to_cpu((__force __be64)drinfo->ino), drinfo->oldnamelen, ++ drinfo->oldname); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* callers have to free the return value */ ++static struct au_drinfo *au_drinfo_read_k(struct file *file, ino_t h_ino) ++{ ++ struct au_drinfo *ret, *drinfo; ++ struct au_drinfo_fdata fdata; ++ int len; ++ loff_t pos; ++ ssize_t ssz; ++ ++ ret = ERR_PTR(-EIO); ++ pos = 0; ++ ssz = vfsub_read_k(file, &fdata, sizeof(fdata), &pos); ++ if (unlikely(ssz != sizeof(fdata))) { ++ AuIOErr("ssz %zd, %u, %pD2\n", ++ ssz, (unsigned int)sizeof(fdata), file); ++ goto out; ++ } ++ ++ fdata.magic = ntohl((__force __be32)fdata.magic); ++ switch (fdata.magic) { ++ case AUFS_DRINFO_MAGIC_V1: ++ break; ++ default: ++ AuIOErr("magic-num 0x%x, 0x%x, %pD2\n", ++ fdata.magic, AUFS_DRINFO_MAGIC_V1, file); ++ goto out; ++ } ++ ++ drinfo = &fdata.drinfo; ++ len = drinfo->oldnamelen; ++ if (!len) { ++ AuIOErr("broken drinfo %pD2\n", file); ++ goto out; ++ } ++ ++ ret = NULL; ++ drinfo->ino = be64_to_cpu((__force __be64)drinfo->ino); ++ if (unlikely(h_ino && drinfo->ino != h_ino)) { ++ AuDbg("ignored i%llu, i%llu, %pD2\n", ++ (unsigned long long)drinfo->ino, ++ (unsigned long long)h_ino, file); ++ goto out; /* success */ ++ } ++ ++ ret = kmalloc(sizeof(*ret) + len, GFP_NOFS); ++ if (unlikely(!ret)) { ++ ret = ERR_PTR(-ENOMEM); ++ AuTraceErrPtr(ret); ++ goto out; ++ } ++ ++ *ret = *drinfo; ++ ssz = vfsub_read_k(file, (void *)ret->oldname, len, &pos); ++ if (unlikely(ssz != len)) { ++ au_kfree_rcu(ret); ++ ret = ERR_PTR(-EIO); ++ AuIOErr("ssz %zd, %u, %pD2\n", ssz, len, file); ++ goto out; ++ } ++ ++ AuDbg("oldname %.*s\n", ret->oldnamelen, ret->oldname); ++ ++out: ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* in order to be revertible */ ++struct au_drinfo_rev_elm { ++ int created; ++ struct dentry *info_dentry; ++ struct au_drinfo *info_last; ++}; ++ ++struct au_drinfo_rev { ++ unsigned char already; ++ aufs_bindex_t nelm; ++ struct au_drinfo_rev_elm elm[]; ++}; ++ ++/* todo: isn't it too large? */ ++struct au_drinfo_store { ++ struct path h_ppath; ++ struct dentry *h_dentry; ++ struct au_drinfo_fdata *fdata; ++ char *infoname; /* inside of whname, just after PFX */ ++ char whname[sizeof(AUFS_WH_DR_INFO_PFX) + AUFS_DIRREN_ENV_VAL_SZ]; ++ aufs_bindex_t btgt, btail; ++ unsigned char no_sio, ++ allocated, /* current size of *fdata */ ++ infonamelen, /* room size for p */ ++ whnamelen, /* length of the generated name */ ++ renameback; /* renamed back */ ++}; ++ ++/* on rename(2) error, the caller should revert it using @elm */ ++static int au_drinfo_do_store(struct au_drinfo_store *w, ++ struct au_drinfo_rev_elm *elm) ++{ ++ int err, len; ++ ssize_t ssz; ++ loff_t pos; ++ struct path infopath = { ++ .mnt = w->h_ppath.mnt ++ }; ++ struct inode *h_dir, *h_inode, *delegated; ++ struct file *infofile; ++ struct qstr *qname; ++ ++ AuDebugOn(elm ++ && memcmp(elm, page_address(ZERO_PAGE(0)), sizeof(*elm))); ++ ++ infopath.dentry = vfsub_lookup_one_len(w->whname, &w->h_ppath, ++ w->whnamelen); ++ AuTraceErrPtr(infopath.dentry); ++ if (IS_ERR(infopath.dentry)) { ++ err = PTR_ERR(infopath.dentry); ++ goto out; ++ } ++ ++ err = 0; ++ h_dir = d_inode(w->h_ppath.dentry); ++ if (elm && d_is_negative(infopath.dentry)) { ++ err = vfsub_create(h_dir, &infopath, 0600, /*want_excl*/true); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out_dput; ++ elm->created = 1; ++ elm->info_dentry = dget(infopath.dentry); ++ } ++ ++ infofile = vfsub_dentry_open(&infopath, O_RDWR); ++ AuTraceErrPtr(infofile); ++ if (IS_ERR(infofile)) { ++ err = PTR_ERR(infofile); ++ goto out_dput; ++ } ++ ++ h_inode = d_inode(infopath.dentry); ++ if (elm && i_size_read(h_inode)) { ++ h_inode = d_inode(w->h_dentry); ++ elm->info_last = au_drinfo_read_k(infofile, h_inode->i_ino); ++ AuTraceErrPtr(elm->info_last); ++ if (IS_ERR(elm->info_last)) { ++ err = PTR_ERR(elm->info_last); ++ elm->info_last = NULL; ++ AuDebugOn(elm->info_dentry); ++ goto out_fput; ++ } ++ } ++ ++ if (elm && w->renameback) { ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, &infopath, &delegated, /*force*/0); ++ AuTraceErr(err); ++ if (unlikely(err == -EWOULDBLOCK)) ++ iput(delegated); ++ goto out_fput; ++ } ++ ++ pos = 0; ++ qname = &w->h_dentry->d_name; ++ len = sizeof(*w->fdata) + qname->len; ++ if (!elm) ++ len = sizeof(*w->fdata) + w->fdata->drinfo.oldnamelen; ++ ssz = vfsub_write_k(infofile, w->fdata, len, &pos); ++ if (ssz == len) { ++ AuDbg("hi%llu, %.*s\n", w->fdata->drinfo.ino, ++ w->fdata->drinfo.oldnamelen, w->fdata->drinfo.oldname); ++ goto out_fput; /* success */ ++ } else { ++ err = -EIO; ++ if (ssz < 0) ++ err = ssz; ++ /* the caller should revert it using @elm */ ++ } ++ ++out_fput: ++ fput(infofile); ++out_dput: ++ dput(infopath.dentry); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++struct au_call_drinfo_do_store_args { ++ int *errp; ++ struct au_drinfo_store *w; ++ struct au_drinfo_rev_elm *elm; ++}; ++ ++static void au_call_drinfo_do_store(void *args) ++{ ++ struct au_call_drinfo_do_store_args *a = args; ++ ++ *a->errp = au_drinfo_do_store(a->w, a->elm); ++} ++ ++static int au_drinfo_store_sio(struct au_drinfo_store *w, ++ struct au_drinfo_rev_elm *elm) ++{ ++ int err, wkq_err; ++ ++ if (w->no_sio) ++ err = au_drinfo_do_store(w, elm); ++ else { ++ struct au_call_drinfo_do_store_args a = { ++ .errp = &err, ++ .w = w, ++ .elm = elm ++ }; ++ wkq_err = au_wkq_wait(au_call_drinfo_do_store, &a); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ AuTraceErr(err); ++ ++ return err; ++} ++ ++static int au_drinfo_store_work_init(struct au_drinfo_store *w, ++ aufs_bindex_t btgt) ++{ ++ int err; ++ ++ memset(w, 0, sizeof(*w)); ++ w->allocated = roundup_pow_of_two(sizeof(*w->fdata) + 40); ++ strcpy(w->whname, AUFS_WH_DR_INFO_PFX); ++ w->infoname = w->whname + sizeof(AUFS_WH_DR_INFO_PFX) - 1; ++ w->infonamelen = sizeof(w->whname) - sizeof(AUFS_WH_DR_INFO_PFX); ++ w->btgt = btgt; ++ w->no_sio = !!uid_eq(current_fsuid(), GLOBAL_ROOT_UID); ++ ++ err = -ENOMEM; ++ w->fdata = kcalloc(1, w->allocated, GFP_NOFS); ++ if (unlikely(!w->fdata)) { ++ AuTraceErr(err); ++ goto out; ++ } ++ w->fdata->magic = (__force uint32_t)htonl(AUFS_DRINFO_MAGIC_V1); ++ err = 0; ++ ++out: ++ return err; ++} ++ ++static void au_drinfo_store_work_fin(struct au_drinfo_store *w) ++{ ++ au_kfree_rcu(w->fdata); ++} ++ ++static void au_drinfo_store_rev(struct au_drinfo_rev *rev, ++ struct au_drinfo_store *w) ++{ ++ struct au_drinfo_rev_elm *elm; ++ struct inode *h_dir, *delegated; ++ int err, nelm; ++ struct path infopath = { ++ .mnt = w->h_ppath.mnt ++ }; ++ ++ h_dir = d_inode(w->h_ppath.dentry); ++ IMustLock(h_dir); ++ ++ err = 0; ++ elm = rev->elm; ++ for (nelm = rev->nelm; nelm > 0; nelm--, elm++) { ++ AuDebugOn(elm->created && elm->info_last); ++ if (elm->created) { ++ AuDbg("here\n"); ++ delegated = NULL; ++ infopath.dentry = elm->info_dentry; ++ err = vfsub_unlink(h_dir, &infopath, &delegated, ++ !w->no_sio); ++ AuTraceErr(err); ++ if (unlikely(err == -EWOULDBLOCK)) ++ iput(delegated); ++ dput(elm->info_dentry); ++ } else if (elm->info_last) { ++ AuDbg("here\n"); ++ w->fdata->drinfo = *elm->info_last; ++ memcpy(w->fdata->drinfo.oldname, ++ elm->info_last->oldname, ++ elm->info_last->oldnamelen); ++ err = au_drinfo_store_sio(w, /*elm*/NULL); ++ au_kfree_rcu(elm->info_last); ++ } ++ if (unlikely(err)) ++ AuIOErr("%d, %s\n", err, w->whname); ++ /* go on even if err */ ++ } ++} ++ ++/* caller has to call au_dr_rename_fin() later */ ++static int au_drinfo_store(struct dentry *dentry, aufs_bindex_t btgt, ++ struct qstr *dst_name, void *_rev) ++{ ++ int err, sz, nelm; ++ aufs_bindex_t bindex, btail; ++ struct au_drinfo_store work; ++ struct au_drinfo_rev *rev, **p; ++ struct au_drinfo_rev_elm *elm; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_hinode *hdir; ++ ++ err = au_drinfo_store_work_init(&work, btgt); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out; ++ ++ err = -ENOMEM; ++ btail = au_dbtaildir(dentry); ++ nelm = btail - btgt; ++ sz = sizeof(*rev) + sizeof(*elm) * nelm; ++ rev = kcalloc(1, sz, GFP_NOFS); ++ if (unlikely(!rev)) { ++ AuTraceErr(err); ++ goto out_args; ++ } ++ rev->nelm = nelm; ++ elm = rev->elm; ++ p = _rev; ++ *p = rev; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ work.h_ppath.dentry = au_h_dptr(dentry, btgt); ++ work.h_ppath.mnt = au_sbr_mnt(sb, btgt); ++ hdir = au_hi(d_inode(dentry), btgt); ++ au_hn_inode_lock_nested(hdir, AuLsc_I_CHILD); ++ for (bindex = btgt + 1; bindex <= btail; bindex++, elm++) { ++ work.h_dentry = au_h_dptr(dentry, bindex); ++ if (!work.h_dentry) ++ continue; ++ ++ err = au_drinfo_construct(&work.fdata, work.h_dentry, ++ &work.allocated); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ break; ++ ++ work.renameback = au_qstreq(&work.h_dentry->d_name, dst_name); ++ br = au_sbr(sb, bindex); ++ work.whnamelen = sizeof(AUFS_WH_DR_INFO_PFX) - 1; ++ work.whnamelen += au_drinfo_name(br, work.infoname, ++ work.infonamelen); ++ AuDbg("whname %.*s, i%llu, %.*s\n", ++ work.whnamelen, work.whname, ++ be64_to_cpu((__force __be64)work.fdata->drinfo.ino), ++ work.fdata->drinfo.oldnamelen, ++ work.fdata->drinfo.oldname); ++ ++ err = au_drinfo_store_sio(&work, elm); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ break; ++ } ++ if (unlikely(err)) { ++ /* revert all drinfo */ ++ au_drinfo_store_rev(rev, &work); ++ au_kfree_try_rcu(rev); ++ *p = NULL; ++ } ++ au_hn_inode_unlock(hdir); ++ ++out_args: ++ au_drinfo_store_work_fin(&work); ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_dr_rename(struct dentry *src, aufs_bindex_t bindex, ++ struct qstr *dst_name, void *_rev) ++{ ++ int err, already; ++ ino_t ino; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_dr_br *dr; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct au_dr_hino *ent; ++ struct au_drinfo_rev *rev, **p; ++ ++ AuDbg("bindex %d\n", bindex); ++ ++ err = -ENOMEM; ++ ent = kmalloc(sizeof(*ent), GFP_NOFS); ++ if (unlikely(!ent)) ++ goto out; ++ ++ sb = src->d_sb; ++ br = au_sbr(sb, bindex); ++ dr = &br->br_dirren; ++ h_dentry = au_h_dptr(src, bindex); ++ h_inode = d_inode(h_dentry); ++ ino = h_inode->i_ino; ++ ent->dr_h_ino = ino; ++ already = au_dr_hino_test_add(dr, ino, ent); ++ AuDbg("b%d, hi%llu, already %d\n", ++ bindex, (unsigned long long)ino, already); ++ ++ err = au_drinfo_store(src, bindex, dst_name, _rev); ++ AuTraceErr(err); ++ if (!err) { ++ p = _rev; ++ rev = *p; ++ rev->already = already; ++ goto out; /* success */ ++ } ++ ++ /* revert */ ++ if (!already) ++ au_dr_hino_del(dr, ent); ++ au_kfree_rcu(ent); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_dr_rename_fin(struct dentry *src, aufs_bindex_t btgt, void *_rev) ++{ ++ struct au_drinfo_rev *rev; ++ struct au_drinfo_rev_elm *elm; ++ int nelm; ++ ++ rev = _rev; ++ elm = rev->elm; ++ for (nelm = rev->nelm; nelm > 0; nelm--, elm++) { ++ dput(elm->info_dentry); ++ au_kfree_rcu(elm->info_last); ++ } ++ au_kfree_try_rcu(rev); ++} ++ ++void au_dr_rename_rev(struct dentry *src, aufs_bindex_t btgt, void *_rev) ++{ ++ int err; ++ struct au_drinfo_store work; ++ struct au_drinfo_rev *rev = _rev; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct inode *h_inode; ++ struct au_dr_br *dr; ++ struct au_dr_hino *ent; ++ ++ err = au_drinfo_store_work_init(&work, btgt); ++ if (unlikely(err)) ++ goto out; ++ ++ sb = src->d_sb; ++ br = au_sbr(sb, btgt); ++ work.h_ppath.dentry = au_h_dptr(src, btgt); ++ work.h_ppath.mnt = au_br_mnt(br); ++ au_drinfo_store_rev(rev, &work); ++ au_drinfo_store_work_fin(&work); ++ if (rev->already) ++ goto out; ++ ++ dr = &br->br_dirren; ++ h_inode = d_inode(work.h_ppath.dentry); ++ ent = au_dr_hino_find(dr, h_inode->i_ino); ++ BUG_ON(!ent); ++ au_dr_hino_del(dr, ent); ++ au_kfree_rcu(ent); ++ ++out: ++ au_kfree_try_rcu(rev); ++ if (unlikely(err)) ++ pr_err("failed to remove dirren info\n"); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct au_drinfo *au_drinfo_do_load(struct path *h_ppath, ++ char *whname, int whnamelen, ++ struct dentry **info_dentry) ++{ ++ struct au_drinfo *drinfo; ++ struct file *f; ++ struct inode *h_dir; ++ struct path infopath; ++ int unlocked; ++ ++ AuDbg("%pd/%.*s\n", h_ppath->dentry, whnamelen, whname); ++ ++ *info_dentry = NULL; ++ drinfo = NULL; ++ unlocked = 0; ++ h_dir = d_inode(h_ppath->dentry); ++ inode_lock_shared_nested(h_dir, AuLsc_I_PARENT); ++ infopath.dentry = vfsub_lookup_one_len(whname, h_ppath, whnamelen); ++ if (IS_ERR(infopath.dentry)) { ++ drinfo = (void *)infopath.dentry; ++ goto out; ++ } ++ ++ if (d_is_negative(infopath.dentry)) ++ goto out_dput; /* success */ ++ ++ infopath.mnt = h_ppath->mnt; ++ f = vfsub_dentry_open(&infopath, O_RDONLY); ++ inode_unlock_shared(h_dir); ++ unlocked = 1; ++ if (IS_ERR(f)) { ++ drinfo = (void *)f; ++ goto out_dput; ++ } ++ ++ drinfo = au_drinfo_read_k(f, /*h_ino*/0); ++ if (IS_ERR_OR_NULL(drinfo)) ++ goto out_fput; ++ ++ AuDbg("oldname %.*s\n", drinfo->oldnamelen, drinfo->oldname); ++ *info_dentry = dget(infopath.dentry); /* keep it alive */ ++ ++out_fput: ++ fput(f); ++out_dput: ++ dput(infopath.dentry); ++out: ++ if (!unlocked) ++ inode_unlock_shared(h_dir); ++ AuTraceErrPtr(drinfo); ++ return drinfo; ++} ++ ++struct au_drinfo_do_load_args { ++ struct au_drinfo **drinfop; ++ struct path *h_ppath; ++ char *whname; ++ int whnamelen; ++ struct dentry **info_dentry; ++}; ++ ++static void au_call_drinfo_do_load(void *args) ++{ ++ struct au_drinfo_do_load_args *a = args; ++ ++ *a->drinfop = au_drinfo_do_load(a->h_ppath, a->whname, a->whnamelen, ++ a->info_dentry); ++} ++ ++struct au_drinfo_load { ++ struct path h_ppath; ++ struct qstr *qname; ++ unsigned char no_sio; ++ ++ aufs_bindex_t ninfo; ++ struct au_drinfo **drinfo; ++}; ++ ++static int au_drinfo_load(struct au_drinfo_load *w, aufs_bindex_t bindex, ++ struct au_branch *br) ++{ ++ int err, wkq_err, whnamelen, e; ++ char whname[sizeof(AUFS_WH_DR_INFO_PFX) + AUFS_DIRREN_ENV_VAL_SZ] ++ = AUFS_WH_DR_INFO_PFX; ++ struct au_drinfo *drinfo; ++ struct qstr oldname; ++ struct inode *h_dir, *delegated; ++ struct dentry *info_dentry; ++ struct path infopath; ++ ++ whnamelen = sizeof(AUFS_WH_DR_INFO_PFX) - 1; ++ whnamelen += au_drinfo_name(br, whname + whnamelen, ++ sizeof(whname) - whnamelen); ++ if (w->no_sio) ++ drinfo = au_drinfo_do_load(&w->h_ppath, whname, whnamelen, ++ &info_dentry); ++ else { ++ struct au_drinfo_do_load_args args = { ++ .drinfop = &drinfo, ++ .h_ppath = &w->h_ppath, ++ .whname = whname, ++ .whnamelen = whnamelen, ++ .info_dentry = &info_dentry ++ }; ++ wkq_err = au_wkq_wait(au_call_drinfo_do_load, &args); ++ if (unlikely(wkq_err)) ++ drinfo = ERR_PTR(wkq_err); ++ } ++ err = PTR_ERR(drinfo); ++ if (IS_ERR_OR_NULL(drinfo)) ++ goto out; ++ ++ err = 0; ++ oldname.len = drinfo->oldnamelen; ++ oldname.name = drinfo->oldname; ++ if (au_qstreq(w->qname, &oldname)) { ++ /* the name is renamed back */ ++ au_kfree_rcu(drinfo); ++ drinfo = NULL; ++ ++ infopath.dentry = info_dentry; ++ infopath.mnt = w->h_ppath.mnt; ++ h_dir = d_inode(w->h_ppath.dentry); ++ delegated = NULL; ++ inode_lock_nested(h_dir, AuLsc_I_PARENT); ++ e = vfsub_unlink(h_dir, &infopath, &delegated, !w->no_sio); ++ inode_unlock(h_dir); ++ if (unlikely(e)) ++ AuIOErr("ignored %d, %pd2\n", e, &infopath.dentry); ++ if (unlikely(e == -EWOULDBLOCK)) ++ iput(delegated); ++ } ++ au_kfree_rcu(w->drinfo[bindex]); ++ w->drinfo[bindex] = drinfo; ++ dput(info_dentry); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_dr_lkup_free(struct au_drinfo **drinfo, int n) ++{ ++ struct au_drinfo **p = drinfo; ++ ++ while (n-- > 0) ++ au_kfree_rcu(*drinfo++); ++ au_kfree_try_rcu(p); ++} ++ ++int au_dr_lkup(struct au_do_lookup_args *lkup, struct dentry *dentry, ++ aufs_bindex_t btgt) ++{ ++ int err, ninfo; ++ struct au_drinfo_load w; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ struct inode *h_dir; ++ struct au_dr_hino *ent; ++ struct super_block *sb; ++ ++ AuDbg("%.*s, name %.*s, whname %.*s, b%d\n", ++ AuLNPair(&dentry->d_name), AuLNPair(&lkup->dirren.dr_name), ++ AuLNPair(&lkup->whname), btgt); ++ ++ sb = dentry->d_sb; ++ bbot = au_sbbot(sb); ++ w.ninfo = bbot + 1; ++ if (!lkup->dirren.drinfo) { ++ lkup->dirren.drinfo = kcalloc(w.ninfo, ++ sizeof(*lkup->dirren.drinfo), ++ GFP_NOFS); ++ if (unlikely(!lkup->dirren.drinfo)) { ++ err = -ENOMEM; ++ goto out; ++ } ++ lkup->dirren.ninfo = w.ninfo; ++ } ++ w.drinfo = lkup->dirren.drinfo; ++ w.no_sio = !!uid_eq(current_fsuid(), GLOBAL_ROOT_UID); ++ w.h_ppath.dentry = au_h_dptr(dentry, btgt); ++ AuDebugOn(!w.h_ppath.dentry); ++ w.h_ppath.mnt = au_sbr_mnt(sb, btgt); ++ w.qname = &dentry->d_name; ++ ++ ninfo = 0; ++ for (bindex = btgt + 1; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ err = au_drinfo_load(&w, bindex, br); ++ if (unlikely(err)) ++ goto out_free; ++ if (w.drinfo[bindex]) ++ ninfo++; ++ } ++ if (!ninfo) { ++ br = au_sbr(sb, btgt); ++ h_dir = d_inode(w.h_ppath.dentry); ++ ent = au_dr_hino_find(&br->br_dirren, h_dir->i_ino); ++ AuDebugOn(!ent); ++ au_dr_hino_del(&br->br_dirren, ent); ++ au_kfree_rcu(ent); ++ } ++ goto out; /* success */ ++ ++out_free: ++ au_dr_lkup_free(lkup->dirren.drinfo, lkup->dirren.ninfo); ++ lkup->dirren.ninfo = 0; ++ lkup->dirren.drinfo = NULL; ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_dr_lkup_fin(struct au_do_lookup_args *lkup) ++{ ++ au_dr_lkup_free(lkup->dirren.drinfo, lkup->dirren.ninfo); ++} ++ ++int au_dr_lkup_name(struct au_do_lookup_args *lkup, aufs_bindex_t btgt) ++{ ++ int err; ++ struct au_drinfo *drinfo; ++ ++ err = 0; ++ if (!lkup->dirren.drinfo) ++ goto out; ++ AuDebugOn(lkup->dirren.ninfo <= btgt); ++ drinfo = lkup->dirren.drinfo[btgt]; ++ if (!drinfo) ++ goto out; ++ ++ au_kfree_try_rcu(lkup->whname.name); ++ lkup->whname.name = NULL; ++ lkup->dirren.dr_name.len = drinfo->oldnamelen; ++ lkup->dirren.dr_name.name = drinfo->oldname; ++ lkup->name = &lkup->dirren.dr_name; ++ err = au_wh_name_alloc(&lkup->whname, lkup->name); ++ if (!err) ++ AuDbg("name %.*s, whname %.*s, b%d\n", ++ AuLNPair(lkup->name), AuLNPair(&lkup->whname), ++ btgt); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_dr_lkup_h_ino(struct au_do_lookup_args *lkup, aufs_bindex_t bindex, ++ ino_t h_ino) ++{ ++ int match; ++ struct au_drinfo *drinfo; ++ ++ match = 1; ++ if (!lkup->dirren.drinfo) ++ goto out; ++ AuDebugOn(lkup->dirren.ninfo <= bindex); ++ drinfo = lkup->dirren.drinfo[bindex]; ++ if (!drinfo) ++ goto out; ++ ++ match = (drinfo->ino == h_ino); ++ AuDbg("match %d\n", match); ++ ++out: ++ return match; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_dr_opt_set(struct super_block *sb) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ err = 0; ++ bbot = au_sbbot(sb); ++ for (bindex = 0; !err && bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ err = au_dr_hino(sb, bindex, /*br*/NULL, &br->br_path); ++ } ++ ++ return err; ++} ++ ++int au_dr_opt_flush(struct super_block *sb) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ err = 0; ++ bbot = au_sbbot(sb); ++ for (bindex = 0; !err && bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_writable(br->br_perm)) ++ err = au_dr_hino(sb, bindex, /*br*/NULL, /*path*/NULL); ++ } ++ ++ return err; ++} ++ ++int au_dr_opt_clr(struct super_block *sb, int no_flush) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ err = 0; ++ if (!no_flush) { ++ err = au_dr_opt_flush(sb); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ au_dr_hino_free(&br->br_dirren); ++ } ++ ++out: ++ return err; ++} +diff -Naur null/fs/aufs/dirren.h linux-5.15.36/fs/aufs/dirren.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/dirren.h 2022-05-10 16:51:39.869744219 +0300 +@@ -0,0 +1,140 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2017-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * renamed dir info ++ */ ++ ++#ifndef __AUFS_DIRREN_H__ ++#define __AUFS_DIRREN_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include "hbl.h" ++ ++#define AuDirren_NHASH 100 ++ ++#ifdef CONFIG_AUFS_DIRREN ++enum au_brid_type { ++ AuBrid_Unset, ++ AuBrid_UUID, ++ AuBrid_FSID, ++ AuBrid_DEV ++}; ++ ++struct au_dr_brid { ++ enum au_brid_type type; ++ union { ++ uuid_t uuid; /* unimplemented yet */ ++ fsid_t fsid; ++ dev_t dev; ++ }; ++}; ++ ++/* 20 is the max digits length of ulong 64 */ ++/* brid-type "_" uuid "_" inum */ ++#define AUFS_DIRREN_FNAME_SZ (1 + 1 + UUID_STRING_LEN + 20) ++#define AUFS_DIRREN_ENV_VAL_SZ (AUFS_DIRREN_FNAME_SZ + 1 + 20) ++ ++struct au_dr_hino { ++ struct hlist_bl_node dr_hnode; ++ ino_t dr_h_ino; ++}; ++ ++struct au_dr_br { ++ struct hlist_bl_head dr_h_ino[AuDirren_NHASH]; ++ struct au_dr_brid dr_brid; ++}; ++ ++struct au_dr_lookup { ++ /* dr_name is pointed by struct au_do_lookup_args.name */ ++ struct qstr dr_name; /* subset of dr_info */ ++ aufs_bindex_t ninfo; ++ struct au_drinfo **drinfo; ++}; ++#else ++struct au_dr_hino; ++/* empty */ ++struct au_dr_br { }; ++struct au_dr_lookup { }; ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_branch; ++struct au_do_lookup_args; ++struct au_hinode; ++#ifdef CONFIG_AUFS_DIRREN ++int au_dr_hino_test_add(struct au_dr_br *dr, ino_t h_ino, ++ struct au_dr_hino *add_ent); ++void au_dr_hino_free(struct au_dr_br *dr); ++int au_dr_br_init(struct super_block *sb, struct au_branch *br, ++ const struct path *path); ++int au_dr_br_fin(struct super_block *sb, struct au_branch *br); ++int au_dr_rename(struct dentry *src, aufs_bindex_t bindex, ++ struct qstr *dst_name, void *_rev); ++void au_dr_rename_fin(struct dentry *src, aufs_bindex_t btgt, void *rev); ++void au_dr_rename_rev(struct dentry *src, aufs_bindex_t bindex, void *rev); ++int au_dr_lkup(struct au_do_lookup_args *lkup, struct dentry *dentry, ++ aufs_bindex_t bindex); ++int au_dr_lkup_name(struct au_do_lookup_args *lkup, aufs_bindex_t btgt); ++int au_dr_lkup_h_ino(struct au_do_lookup_args *lkup, aufs_bindex_t bindex, ++ ino_t h_ino); ++void au_dr_lkup_fin(struct au_do_lookup_args *lkup); ++int au_dr_opt_set(struct super_block *sb); ++int au_dr_opt_flush(struct super_block *sb); ++int au_dr_opt_clr(struct super_block *sb, int no_flush); ++#else ++AuStubInt0(au_dr_hino_test_add, struct au_dr_br *dr, ino_t h_ino, ++ struct au_dr_hino *add_ent); ++AuStubVoid(au_dr_hino_free, struct au_dr_br *dr); ++AuStubInt0(au_dr_br_init, struct super_block *sb, struct au_branch *br, ++ const struct path *path); ++AuStubInt0(au_dr_br_fin, struct super_block *sb, struct au_branch *br); ++AuStubInt0(au_dr_rename, struct dentry *src, aufs_bindex_t bindex, ++ struct qstr *dst_name, void *_rev); ++AuStubVoid(au_dr_rename_fin, struct dentry *src, aufs_bindex_t btgt, void *rev); ++AuStubVoid(au_dr_rename_rev, struct dentry *src, aufs_bindex_t bindex, ++ void *rev); ++AuStubInt0(au_dr_lkup, struct au_do_lookup_args *lkup, struct dentry *dentry, ++ aufs_bindex_t bindex); ++AuStubInt0(au_dr_lkup_name, struct au_do_lookup_args *lkup, aufs_bindex_t btgt); ++AuStubInt0(au_dr_lkup_h_ino, struct au_do_lookup_args *lkup, ++ aufs_bindex_t bindex, ino_t h_ino); ++AuStubVoid(au_dr_lkup_fin, struct au_do_lookup_args *lkup); ++AuStubInt0(au_dr_opt_set, struct super_block *sb); ++AuStubInt0(au_dr_opt_flush, struct super_block *sb); ++AuStubInt0(au_dr_opt_clr, struct super_block *sb, int no_flush); ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_DIRREN ++static inline int au_dr_ihash(ino_t h_ino) ++{ ++ return h_ino % AuDirren_NHASH; ++} ++#else ++AuStubInt0(au_dr_ihash, ino_t h_ino); ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DIRREN_H__ */ +diff -Naur null/fs/aufs/dynop.c linux-5.15.36/fs/aufs/dynop.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/dynop.c 2022-05-10 16:51:39.869744219 +0300 +@@ -0,0 +1,368 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2010-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * dynamically customizable operations for regular files ++ */ ++ ++#include "aufs.h" ++ ++#define DyPrSym(key) AuDbgSym(key->dk_op.dy_hop) ++ ++/* ++ * How large will these lists be? ++ * Usually just a few elements, 20-30 at most for each, I guess. ++ */ ++static struct hlist_bl_head dynop[AuDyLast]; ++ ++static struct au_dykey *dy_gfind_get(struct hlist_bl_head *hbl, ++ const void *h_op) ++{ ++ struct au_dykey *key, *tmp; ++ struct hlist_bl_node *pos; ++ ++ key = NULL; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(tmp, pos, hbl, dk_hnode) ++ if (tmp->dk_op.dy_hop == h_op) { ++ if (kref_get_unless_zero(&tmp->dk_kref)) ++ key = tmp; ++ break; ++ } ++ hlist_bl_unlock(hbl); ++ ++ return key; ++} ++ ++static struct au_dykey *dy_bradd(struct au_branch *br, struct au_dykey *key) ++{ ++ struct au_dykey **k, *found; ++ const void *h_op = key->dk_op.dy_hop; ++ int i; ++ ++ found = NULL; ++ k = br->br_dykey; ++ for (i = 0; i < AuBrDynOp; i++) ++ if (k[i]) { ++ if (k[i]->dk_op.dy_hop == h_op) { ++ found = k[i]; ++ break; ++ } ++ } else ++ break; ++ if (!found) { ++ spin_lock(&br->br_dykey_lock); ++ for (; i < AuBrDynOp; i++) ++ if (k[i]) { ++ if (k[i]->dk_op.dy_hop == h_op) { ++ found = k[i]; ++ break; ++ } ++ } else { ++ k[i] = key; ++ break; ++ } ++ spin_unlock(&br->br_dykey_lock); ++ BUG_ON(i == AuBrDynOp); /* expand the array */ ++ } ++ ++ return found; ++} ++ ++/* kref_get() if @key is already added */ ++static struct au_dykey *dy_gadd(struct hlist_bl_head *hbl, struct au_dykey *key) ++{ ++ struct au_dykey *tmp, *found; ++ struct hlist_bl_node *pos; ++ const void *h_op = key->dk_op.dy_hop; ++ ++ found = NULL; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(tmp, pos, hbl, dk_hnode) ++ if (tmp->dk_op.dy_hop == h_op) { ++ if (kref_get_unless_zero(&tmp->dk_kref)) ++ found = tmp; ++ break; ++ } ++ if (!found) ++ hlist_bl_add_head(&key->dk_hnode, hbl); ++ hlist_bl_unlock(hbl); ++ ++ if (!found) ++ DyPrSym(key); ++ return found; ++} ++ ++static void dy_free_rcu(struct rcu_head *rcu) ++{ ++ struct au_dykey *key; ++ ++ key = container_of(rcu, struct au_dykey, dk_rcu); ++ DyPrSym(key); ++ kfree(key); ++} ++ ++static void dy_free(struct kref *kref) ++{ ++ struct au_dykey *key; ++ struct hlist_bl_head *hbl; ++ ++ key = container_of(kref, struct au_dykey, dk_kref); ++ hbl = dynop + key->dk_op.dy_type; ++ au_hbl_del(&key->dk_hnode, hbl); ++ call_rcu(&key->dk_rcu, dy_free_rcu); ++} ++ ++void au_dy_put(struct au_dykey *key) ++{ ++ kref_put(&key->dk_kref, dy_free); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define DyDbgSize(cnt, op) AuDebugOn(cnt != sizeof(op)/sizeof(void *)) ++ ++#ifdef CONFIG_AUFS_DEBUG ++#define DyDbgDeclare(cnt) unsigned int cnt = 0 ++#define DyDbgInc(cnt) do { cnt++; } while (0) ++#else ++#define DyDbgDeclare(cnt) do {} while (0) ++#define DyDbgInc(cnt) do {} while (0) ++#endif ++ ++#define DySet(func, dst, src, h_op, h_sb) do { \ ++ DyDbgInc(cnt); \ ++ if (h_op->func) { \ ++ if (src.func) \ ++ dst.func = src.func; \ ++ else \ ++ AuDbg("%s %s\n", au_sbtype(h_sb), #func); \ ++ } \ ++} while (0) ++ ++#define DySetForce(func, dst, src) do { \ ++ AuDebugOn(!src.func); \ ++ DyDbgInc(cnt); \ ++ dst.func = src.func; \ ++} while (0) ++ ++#define DySetAop(func) \ ++ DySet(func, dyaop->da_op, aufs_aop, h_aop, h_sb) ++#define DySetAopForce(func) \ ++ DySetForce(func, dyaop->da_op, aufs_aop) ++ ++static void dy_aop(struct au_dykey *key, const void *h_op, ++ struct super_block *h_sb __maybe_unused) ++{ ++ struct au_dyaop *dyaop = (void *)key; ++ const struct address_space_operations *h_aop = h_op; ++ DyDbgDeclare(cnt); ++ ++ AuDbg("%s\n", au_sbtype(h_sb)); ++ ++ DySetAop(writepage); ++ DySetAopForce(readpage); /* force */ ++ DySetAop(writepages); ++ DySetAop(set_page_dirty); ++ DySetAop(readpages); ++ DySetAop(readahead); ++ DySetAop(write_begin); ++ DySetAop(write_end); ++ DySetAop(bmap); ++ DySetAop(invalidatepage); ++ DySetAop(releasepage); ++ DySetAop(freepage); ++ /* this one will be changed according to an aufs mount option */ ++ DySetAop(direct_IO); ++ DySetAop(migratepage); ++ DySetAop(isolate_page); ++ DySetAop(putback_page); ++ DySetAop(launder_page); ++ DySetAop(is_partially_uptodate); ++ DySetAop(is_dirty_writeback); ++ DySetAop(error_remove_page); ++ DySetAop(swap_activate); ++ DySetAop(swap_deactivate); ++ ++ DyDbgSize(cnt, *h_aop); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void dy_bug(struct kref *kref) ++{ ++ BUG(); ++} ++ ++static struct au_dykey *dy_get(struct au_dynop *op, struct au_branch *br) ++{ ++ struct au_dykey *key, *old; ++ struct hlist_bl_head *hbl; ++ struct op { ++ unsigned int sz; ++ void (*set)(struct au_dykey *key, const void *h_op, ++ struct super_block *h_sb __maybe_unused); ++ }; ++ static const struct op a[] = { ++ [AuDy_AOP] = { ++ .sz = sizeof(struct au_dyaop), ++ .set = dy_aop ++ } ++ }; ++ const struct op *p; ++ ++ hbl = dynop + op->dy_type; ++ key = dy_gfind_get(hbl, op->dy_hop); ++ if (key) ++ goto out_add; /* success */ ++ ++ p = a + op->dy_type; ++ key = kzalloc(p->sz, GFP_NOFS); ++ if (unlikely(!key)) { ++ key = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ ++ key->dk_op.dy_hop = op->dy_hop; ++ kref_init(&key->dk_kref); ++ p->set(key, op->dy_hop, au_br_sb(br)); ++ old = dy_gadd(hbl, key); ++ if (old) { ++ au_kfree_rcu(key); ++ key = old; ++ } ++ ++out_add: ++ old = dy_bradd(br, key); ++ if (old) ++ /* its ref-count should never be zero here */ ++ kref_put(&key->dk_kref, dy_bug); ++out: ++ return key; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * Aufs prohibits O_DIRECT by default even if the branch supports it. ++ * This behaviour is necessary to return an error from open(O_DIRECT) instead ++ * of the succeeding I/O. The dio mount option enables O_DIRECT and makes ++ * open(O_DIRECT) always succeed, but the succeeding I/O may return an error. ++ * See the aufs manual in detail. ++ */ ++static void dy_adx(struct au_dyaop *dyaop, int do_dx) ++{ ++ if (!do_dx) ++ dyaop->da_op.direct_IO = NULL; ++ else ++ dyaop->da_op.direct_IO = aufs_aop.direct_IO; ++} ++ ++static struct au_dyaop *dy_aget(struct au_branch *br, ++ const struct address_space_operations *h_aop, ++ int do_dx) ++{ ++ struct au_dyaop *dyaop; ++ struct au_dynop op; ++ ++ op.dy_type = AuDy_AOP; ++ op.dy_haop = h_aop; ++ dyaop = (void *)dy_get(&op, br); ++ if (IS_ERR(dyaop)) ++ goto out; ++ dy_adx(dyaop, do_dx); ++ ++out: ++ return dyaop; ++} ++ ++int au_dy_iaop(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode) ++{ ++ int err, do_dx; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_dyaop *dyaop; ++ ++ AuDebugOn(!S_ISREG(h_inode->i_mode)); ++ IiMustWriteLock(inode); ++ ++ sb = inode->i_sb; ++ br = au_sbr(sb, bindex); ++ do_dx = !!au_opt_test(au_mntflags(sb), DIO); ++ dyaop = dy_aget(br, h_inode->i_mapping->a_ops, do_dx); ++ err = PTR_ERR(dyaop); ++ if (IS_ERR(dyaop)) ++ /* unnecessary to call dy_fput() */ ++ goto out; ++ ++ err = 0; ++ inode->i_mapping->a_ops = &dyaop->da_op; ++ ++out: ++ return err; ++} ++ ++/* ++ * Is it safe to replace a_ops during the inode/file is in operation? ++ * Yes, I hope so. ++ */ ++int au_dy_irefresh(struct inode *inode) ++{ ++ int err; ++ aufs_bindex_t btop; ++ struct inode *h_inode; ++ ++ err = 0; ++ if (S_ISREG(inode->i_mode)) { ++ btop = au_ibtop(inode); ++ h_inode = au_h_iptr(inode, btop); ++ err = au_dy_iaop(inode, btop, h_inode); ++ } ++ return err; ++} ++ ++void au_dy_arefresh(int do_dx) ++{ ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_dykey *key; ++ ++ hbl = dynop + AuDy_AOP; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(key, pos, hbl, dk_hnode) ++ dy_adx((void *)key, do_dx); ++ hlist_bl_unlock(hbl); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void __init au_dy_init(void) ++{ ++ int i; ++ ++ for (i = 0; i < AuDyLast; i++) ++ INIT_HLIST_BL_HEAD(dynop + i); ++} ++ ++void au_dy_fin(void) ++{ ++ int i; ++ ++ for (i = 0; i < AuDyLast; i++) ++ WARN_ON(!hlist_bl_empty(dynop + i)); ++} +diff -Naur null/fs/aufs/dynop.h linux-5.15.36/fs/aufs/dynop.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/dynop.h 2022-05-10 16:51:39.870744219 +0300 +@@ -0,0 +1,77 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2010-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * dynamically customizable operations (for regular files only) ++ */ ++ ++#ifndef __AUFS_DYNOP_H__ ++#define __AUFS_DYNOP_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++ ++enum {AuDy_AOP, AuDyLast}; ++ ++struct au_dynop { ++ int dy_type; ++ union { ++ const void *dy_hop; ++ const struct address_space_operations *dy_haop; ++ }; ++}; ++ ++struct au_dykey { ++ union { ++ struct hlist_bl_node dk_hnode; ++ struct rcu_head dk_rcu; ++ }; ++ struct au_dynop dk_op; ++ ++ /* ++ * during I am in the branch local array, kref is gotten. when the ++ * branch is removed, kref is put. ++ */ ++ struct kref dk_kref; ++}; ++ ++/* stop unioning since their sizes are very different from each other */ ++struct au_dyaop { ++ struct au_dykey da_key; ++ struct address_space_operations da_op; /* not const */ ++}; ++/* make sure that 'struct au_dykey *' can be any type */ ++static_assert(!offsetof(struct au_dyaop, da_key)); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dynop.c */ ++struct au_branch; ++void au_dy_put(struct au_dykey *key); ++int au_dy_iaop(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode); ++int au_dy_irefresh(struct inode *inode); ++void au_dy_arefresh(int do_dio); ++ ++void __init au_dy_init(void); ++void au_dy_fin(void); ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DYNOP_H__ */ +diff -Naur null/fs/aufs/export.c linux-5.15.36/fs/aufs/export.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/export.c 2022-05-10 16:51:39.870744219 +0300 +@@ -0,0 +1,830 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * export via nfs ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++union conv { ++#ifdef CONFIG_AUFS_INO_T_64 ++ __u32 a[2]; ++#else ++ __u32 a[1]; ++#endif ++ ino_t ino; ++}; ++ ++static ino_t decode_ino(__u32 *a) ++{ ++ union conv u; ++ ++ BUILD_BUG_ON(sizeof(u.ino) != sizeof(u.a)); ++ u.a[0] = a[0]; ++#ifdef CONFIG_AUFS_INO_T_64 ++ u.a[1] = a[1]; ++#endif ++ return u.ino; ++} ++ ++static void encode_ino(__u32 *a, ino_t ino) ++{ ++ union conv u; ++ ++ u.ino = ino; ++ a[0] = u.a[0]; ++#ifdef CONFIG_AUFS_INO_T_64 ++ a[1] = u.a[1]; ++#endif ++} ++ ++/* NFS file handle */ ++enum { ++ Fh_br_id, ++ Fh_sigen, ++#ifdef CONFIG_AUFS_INO_T_64 ++ /* support 64bit inode number */ ++ Fh_ino1, ++ Fh_ino2, ++ Fh_dir_ino1, ++ Fh_dir_ino2, ++#else ++ Fh_ino1, ++ Fh_dir_ino1, ++#endif ++ Fh_igen, ++ Fh_h_type, ++ Fh_tail, ++ ++ Fh_ino = Fh_ino1, ++ Fh_dir_ino = Fh_dir_ino1 ++}; ++ ++static int au_test_anon(struct dentry *dentry) ++{ ++ /* note: read d_flags without d_lock */ ++ return !!(dentry->d_flags & DCACHE_DISCONNECTED); ++} ++ ++int au_test_nfsd(void) ++{ ++ int ret; ++ struct task_struct *tsk = current; ++ char comm[sizeof(tsk->comm)]; ++ ++ ret = 0; ++ if (tsk->flags & PF_KTHREAD) { ++ get_task_comm(comm, tsk); ++ ret = !strcmp(comm, "nfsd"); ++ } ++ ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* inode generation external table */ ++ ++void au_xigen_inc(struct inode *inode) ++{ ++ loff_t pos; ++ ssize_t sz; ++ __u32 igen; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ ++ sb = inode->i_sb; ++ AuDebugOn(!au_opt_test(au_mntflags(sb), XINO)); ++ ++ sbinfo = au_sbi(sb); ++ pos = inode->i_ino; ++ pos *= sizeof(igen); ++ igen = inode->i_generation + 1; ++ sz = xino_fwrite(sbinfo->si_xigen, &igen, sizeof(igen), &pos); ++ if (sz == sizeof(igen)) ++ return; /* success */ ++ ++ if (unlikely(sz >= 0)) ++ AuIOErr("xigen error (%zd)\n", sz); ++} ++ ++int au_xigen_new(struct inode *inode) ++{ ++ int err; ++ loff_t pos; ++ ssize_t sz; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ ++ err = 0; ++ /* todo: dirty, at mount time */ ++ if (inode->i_ino == AUFS_ROOT_INO) ++ goto out; ++ sb = inode->i_sb; ++ SiMustAnyLock(sb); ++ if (unlikely(!au_opt_test(au_mntflags(sb), XINO))) ++ goto out; ++ ++ err = -EFBIG; ++ pos = inode->i_ino; ++ if (unlikely(au_loff_max / sizeof(inode->i_generation) - 1 < pos)) { ++ AuIOErr1("too large i%lld\n", pos); ++ goto out; ++ } ++ pos *= sizeof(inode->i_generation); ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ file = sbinfo->si_xigen; ++ BUG_ON(!file); ++ ++ if (vfsub_f_size_read(file) ++ < pos + sizeof(inode->i_generation)) { ++ inode->i_generation = atomic_inc_return(&sbinfo->si_xigen_next); ++ sz = xino_fwrite(file, &inode->i_generation, ++ sizeof(inode->i_generation), &pos); ++ } else ++ sz = xino_fread(file, &inode->i_generation, ++ sizeof(inode->i_generation), &pos); ++ if (sz == sizeof(inode->i_generation)) ++ goto out; /* success */ ++ ++ err = sz; ++ if (unlikely(sz >= 0)) { ++ err = -EIO; ++ AuIOErr("xigen error (%zd)\n", sz); ++ } ++ ++out: ++ return err; ++} ++ ++int au_xigen_set(struct super_block *sb, struct path *path) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ file = au_xino_create2(sb, path, sbinfo->si_xigen); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ err = 0; ++ if (sbinfo->si_xigen) ++ fput(sbinfo->si_xigen); ++ sbinfo->si_xigen = file; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_xigen_clr(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ if (sbinfo->si_xigen) { ++ fput(sbinfo->si_xigen); ++ sbinfo->si_xigen = NULL; ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry *decode_by_ino(struct super_block *sb, ino_t ino, ++ ino_t dir_ino) ++{ ++ struct dentry *dentry, *d; ++ struct inode *inode; ++ unsigned int sigen; ++ ++ dentry = NULL; ++ inode = ilookup(sb, ino); ++ if (!inode) ++ goto out; ++ ++ dentry = ERR_PTR(-ESTALE); ++ sigen = au_sigen(sb); ++ if (unlikely(au_is_bad_inode(inode) ++ || IS_DEADDIR(inode) ++ || sigen != au_iigen(inode, NULL))) ++ goto out_iput; ++ ++ dentry = NULL; ++ if (!dir_ino || S_ISDIR(inode->i_mode)) ++ dentry = d_find_alias(inode); ++ else { ++ spin_lock(&inode->i_lock); ++ hlist_for_each_entry(d, &inode->i_dentry, d_u.d_alias) { ++ spin_lock(&d->d_lock); ++ if (!au_test_anon(d) ++ && d_inode(d->d_parent)->i_ino == dir_ino) { ++ dentry = dget_dlock(d); ++ spin_unlock(&d->d_lock); ++ break; ++ } ++ spin_unlock(&d->d_lock); ++ } ++ spin_unlock(&inode->i_lock); ++ } ++ if (unlikely(dentry && au_digen_test(dentry, sigen))) { ++ /* need to refresh */ ++ dput(dentry); ++ dentry = NULL; ++ } ++ ++out_iput: ++ iput(inode); ++out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* todo: dirty? */ ++/* if exportfs_decode_fh() passed vfsmount*, we could be happy */ ++ ++struct au_compare_mnt_args { ++ /* input */ ++ struct super_block *sb; ++ ++ /* output */ ++ struct vfsmount *mnt; ++}; ++ ++static int au_compare_mnt(struct vfsmount *mnt, void *arg) ++{ ++ struct au_compare_mnt_args *a = arg; ++ ++ if (mnt->mnt_sb != a->sb) ++ return 0; ++ a->mnt = mntget(mnt); ++ return 1; ++} ++ ++static struct vfsmount *au_mnt_get(struct super_block *sb) ++{ ++ int err; ++ struct path root; ++ struct au_compare_mnt_args args = { ++ .sb = sb ++ }; ++ ++ get_fs_root(current->fs, &root); ++ rcu_read_lock(); ++ err = iterate_mounts(au_compare_mnt, &args, root.mnt); ++ rcu_read_unlock(); ++ path_put(&root); ++ AuDebugOn(!err); ++ AuDebugOn(!args.mnt); ++ return args.mnt; ++} ++ ++struct au_nfsd_si_lock { ++ unsigned int sigen; ++ aufs_bindex_t bindex, br_id; ++ unsigned char force_lock; ++}; ++ ++static int si_nfsd_read_lock(struct super_block *sb, ++ struct au_nfsd_si_lock *nsi_lock) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ ++ si_read_lock(sb, AuLock_FLUSH); ++ ++ /* branch id may be wrapped around */ ++ err = 0; ++ bindex = au_br_index(sb, nsi_lock->br_id); ++ if (bindex >= 0 && nsi_lock->sigen + AUFS_BRANCH_MAX > au_sigen(sb)) ++ goto out; /* success */ ++ ++ err = -ESTALE; ++ bindex = -1; ++ if (!nsi_lock->force_lock) ++ si_read_unlock(sb); ++ ++out: ++ nsi_lock->bindex = bindex; ++ return err; ++} ++ ++struct find_name_by_ino { ++ struct dir_context ctx; ++ int called, found; ++ ino_t ino; ++ char *name; ++ int namelen; ++}; ++ ++static int ++find_name_by_ino(struct dir_context *ctx, const char *name, int namelen, ++ loff_t offset, u64 ino, unsigned int d_type) ++{ ++ struct find_name_by_ino *a = container_of(ctx, struct find_name_by_ino, ++ ctx); ++ ++ a->called++; ++ if (a->ino != ino) ++ return 0; ++ ++ memcpy(a->name, name, namelen); ++ a->namelen = namelen; ++ a->found = 1; ++ return 1; ++} ++ ++static struct dentry *au_lkup_by_ino(struct path *path, ino_t ino, ++ struct au_nfsd_si_lock *nsi_lock) ++{ ++ struct dentry *dentry, *parent; ++ struct file *file; ++ struct inode *dir; ++ struct find_name_by_ino arg = { ++ .ctx = { ++ .actor = find_name_by_ino ++ } ++ }; ++ int err; ++ ++ parent = path->dentry; ++ if (nsi_lock) ++ si_read_unlock(parent->d_sb); ++ file = vfsub_dentry_open(path, au_dir_roflags); ++ dentry = (void *)file; ++ if (IS_ERR(file)) ++ goto out; ++ ++ dentry = ERR_PTR(-ENOMEM); ++ arg.name = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!arg.name)) ++ goto out_file; ++ arg.ino = ino; ++ arg.found = 0; ++ do { ++ arg.called = 0; ++ /* smp_mb(); */ ++ err = vfsub_iterate_dir(file, &arg.ctx); ++ } while (!err && !arg.found && arg.called); ++ dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_name; ++ /* instead of ENOENT */ ++ dentry = ERR_PTR(-ESTALE); ++ if (!arg.found) ++ goto out_name; ++ ++ /* do not call vfsub_lkup_one() */ ++ dir = d_inode(parent); ++ dentry = vfsub_lookup_one_len_unlocked(arg.name, path, arg.namelen); ++ AuTraceErrPtr(dentry); ++ if (IS_ERR(dentry)) ++ goto out_name; ++ AuDebugOn(au_test_anon(dentry)); ++ if (unlikely(d_really_is_negative(dentry))) { ++ dput(dentry); ++ dentry = ERR_PTR(-ENOENT); ++ } ++ ++out_name: ++ free_page((unsigned long)arg.name); ++out_file: ++ fput(file); ++out: ++ if (unlikely(nsi_lock ++ && si_nfsd_read_lock(parent->d_sb, nsi_lock) < 0)) ++ if (!IS_ERR(dentry)) { ++ dput(dentry); ++ dentry = ERR_PTR(-ESTALE); ++ } ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++static struct dentry *decode_by_dir_ino(struct super_block *sb, ino_t ino, ++ ino_t dir_ino, ++ struct au_nfsd_si_lock *nsi_lock) ++{ ++ struct dentry *dentry; ++ struct path path; ++ ++ if (dir_ino != AUFS_ROOT_INO) { ++ path.dentry = decode_by_ino(sb, dir_ino, 0); ++ dentry = path.dentry; ++ if (!path.dentry || IS_ERR(path.dentry)) ++ goto out; ++ AuDebugOn(au_test_anon(path.dentry)); ++ } else ++ path.dentry = dget(sb->s_root); ++ ++ path.mnt = au_mnt_get(sb); ++ dentry = au_lkup_by_ino(&path, ino, nsi_lock); ++ path_put(&path); ++ ++out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int h_acceptable(void *expv, struct dentry *dentry) ++{ ++ return 1; ++} ++ ++static char *au_build_path(struct dentry *h_parent, struct path *h_rootpath, ++ char *buf, int len, struct super_block *sb) ++{ ++ char *p; ++ int n; ++ struct path path; ++ ++ p = d_path(h_rootpath, buf, len); ++ if (IS_ERR(p)) ++ goto out; ++ n = strlen(p); ++ ++ path.mnt = h_rootpath->mnt; ++ path.dentry = h_parent; ++ p = d_path(&path, buf, len); ++ if (IS_ERR(p)) ++ goto out; ++ if (n != 1) ++ p += n; ++ ++ path.mnt = au_mnt_get(sb); ++ path.dentry = sb->s_root; ++ p = d_path(&path, buf, len - strlen(p)); ++ mntput(path.mnt); ++ if (IS_ERR(p)) ++ goto out; ++ if (n != 1) ++ p[strlen(p)] = '/'; ++ ++out: ++ AuTraceErrPtr(p); ++ return p; ++} ++ ++static ++struct dentry *decode_by_path(struct super_block *sb, ino_t ino, __u32 *fh, ++ int fh_len, struct au_nfsd_si_lock *nsi_lock) ++{ ++ struct dentry *dentry, *h_parent, *root; ++ struct super_block *h_sb; ++ char *pathname, *p; ++ struct vfsmount *h_mnt; ++ struct au_branch *br; ++ int err; ++ struct path path; ++ ++ br = au_sbr(sb, nsi_lock->bindex); ++ h_mnt = au_br_mnt(br); ++ h_sb = h_mnt->mnt_sb; ++ /* todo: call lower fh_to_dentry()? fh_to_parent()? */ ++ lockdep_off(); ++ h_parent = exportfs_decode_fh(h_mnt, (void *)(fh + Fh_tail), ++ fh_len - Fh_tail, fh[Fh_h_type], ++ h_acceptable, /*context*/NULL); ++ lockdep_on(); ++ dentry = h_parent; ++ if (unlikely(!h_parent || IS_ERR(h_parent))) { ++ AuWarn1("%s decode_fh failed, %ld\n", ++ au_sbtype(h_sb), PTR_ERR(h_parent)); ++ goto out; ++ } ++ dentry = NULL; ++ if (unlikely(au_test_anon(h_parent))) { ++ AuWarn1("%s decode_fh returned a disconnected dentry\n", ++ au_sbtype(h_sb)); ++ goto out_h_parent; ++ } ++ ++ dentry = ERR_PTR(-ENOMEM); ++ pathname = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!pathname)) ++ goto out_h_parent; ++ ++ root = sb->s_root; ++ path.mnt = h_mnt; ++ di_read_lock_parent(root, !AuLock_IR); ++ path.dentry = au_h_dptr(root, nsi_lock->bindex); ++ di_read_unlock(root, !AuLock_IR); ++ p = au_build_path(h_parent, &path, pathname, PAGE_SIZE, sb); ++ dentry = (void *)p; ++ if (IS_ERR(p)) ++ goto out_pathname; ++ ++ si_read_unlock(sb); ++ err = vfsub_kern_path(p, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); ++ dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_relock; ++ ++ dentry = ERR_PTR(-ENOENT); ++ AuDebugOn(au_test_anon(path.dentry)); ++ if (unlikely(d_really_is_negative(path.dentry))) ++ goto out_path; ++ ++ if (ino != d_inode(path.dentry)->i_ino) ++ dentry = au_lkup_by_ino(&path, ino, /*nsi_lock*/NULL); ++ else ++ dentry = dget(path.dentry); ++ ++out_path: ++ path_put(&path); ++out_relock: ++ if (unlikely(si_nfsd_read_lock(sb, nsi_lock) < 0)) ++ if (!IS_ERR(dentry)) { ++ dput(dentry); ++ dentry = ERR_PTR(-ESTALE); ++ } ++out_pathname: ++ free_page((unsigned long)pathname); ++out_h_parent: ++ dput(h_parent); ++out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry * ++aufs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, ++ int fh_type) ++{ ++ struct dentry *dentry; ++ __u32 *fh = fid->raw; ++ struct au_branch *br; ++ ino_t ino, dir_ino; ++ struct au_nfsd_si_lock nsi_lock = { ++ .force_lock = 0 ++ }; ++ ++ dentry = ERR_PTR(-ESTALE); ++ /* it should never happen, but the file handle is unreliable */ ++ if (unlikely(fh_len < Fh_tail)) ++ goto out; ++ nsi_lock.sigen = fh[Fh_sigen]; ++ nsi_lock.br_id = fh[Fh_br_id]; ++ ++ /* branch id may be wrapped around */ ++ br = NULL; ++ if (unlikely(si_nfsd_read_lock(sb, &nsi_lock))) ++ goto out; ++ nsi_lock.force_lock = 1; ++ ++ /* is this inode still cached? */ ++ ino = decode_ino(fh + Fh_ino); ++ /* it should never happen */ ++ if (unlikely(ino == AUFS_ROOT_INO)) ++ goto out_unlock; ++ ++ dir_ino = decode_ino(fh + Fh_dir_ino); ++ dentry = decode_by_ino(sb, ino, dir_ino); ++ if (IS_ERR(dentry)) ++ goto out_unlock; ++ if (dentry) ++ goto accept; ++ ++ /* is the parent dir cached? */ ++ br = au_sbr(sb, nsi_lock.bindex); ++ au_lcnt_inc(&br->br_nfiles); ++ dentry = decode_by_dir_ino(sb, ino, dir_ino, &nsi_lock); ++ if (IS_ERR(dentry)) ++ goto out_unlock; ++ if (dentry) ++ goto accept; ++ ++ /* lookup path */ ++ dentry = decode_by_path(sb, ino, fh, fh_len, &nsi_lock); ++ if (IS_ERR(dentry)) ++ goto out_unlock; ++ if (unlikely(!dentry)) ++ /* todo?: make it ESTALE */ ++ goto out_unlock; ++ ++accept: ++ if (!au_digen_test(dentry, au_sigen(sb)) ++ && d_inode(dentry)->i_generation == fh[Fh_igen]) ++ goto out_unlock; /* success */ ++ ++ dput(dentry); ++ dentry = ERR_PTR(-ESTALE); ++out_unlock: ++ if (br) ++ au_lcnt_dec(&br->br_nfiles); ++ si_read_unlock(sb); ++out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++#if 0 /* reserved for future use */ ++/* support subtreecheck option */ ++static struct dentry *aufs_fh_to_parent(struct super_block *sb, struct fid *fid, ++ int fh_len, int fh_type) ++{ ++ struct dentry *parent; ++ __u32 *fh = fid->raw; ++ ino_t dir_ino; ++ ++ dir_ino = decode_ino(fh + Fh_dir_ino); ++ parent = decode_by_ino(sb, dir_ino, 0); ++ if (IS_ERR(parent)) ++ goto out; ++ if (!parent) ++ parent = decode_by_path(sb, au_br_index(sb, fh[Fh_br_id]), ++ dir_ino, fh, fh_len); ++ ++out: ++ AuTraceErrPtr(parent); ++ return parent; ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_encode_fh(struct inode *inode, __u32 *fh, int *max_len, ++ struct inode *dir) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct super_block *sb, *h_sb; ++ struct dentry *dentry, *parent, *h_parent; ++ struct inode *h_dir; ++ struct au_branch *br; ++ ++ err = -ENOSPC; ++ if (unlikely(*max_len <= Fh_tail)) { ++ AuWarn1("NFSv2 client (max_len %d)?\n", *max_len); ++ goto out; ++ } ++ ++ err = FILEID_ROOT; ++ if (inode->i_ino == AUFS_ROOT_INO) { ++ AuDebugOn(inode->i_ino != AUFS_ROOT_INO); ++ goto out; ++ } ++ ++ h_parent = NULL; ++ sb = inode->i_sb; ++ err = si_read_lock(sb, AuLock_FLUSH); ++ if (unlikely(err)) ++ goto out; ++ ++#ifdef CONFIG_AUFS_DEBUG ++ if (unlikely(!au_opt_test(au_mntflags(sb), XINO))) ++ AuWarn1("NFS-exporting requires xino\n"); ++#endif ++ err = -EIO; ++ parent = NULL; ++ ii_read_lock_child(inode); ++ bindex = au_ibtop(inode); ++ if (!dir) { ++ dentry = d_find_any_alias(inode); ++ if (unlikely(!dentry)) ++ goto out_unlock; ++ AuDebugOn(au_test_anon(dentry)); ++ parent = dget_parent(dentry); ++ dput(dentry); ++ if (unlikely(!parent)) ++ goto out_unlock; ++ if (d_really_is_positive(parent)) ++ dir = d_inode(parent); ++ } ++ ++ ii_read_lock_parent(dir); ++ h_dir = au_h_iptr(dir, bindex); ++ ii_read_unlock(dir); ++ if (unlikely(!h_dir)) ++ goto out_parent; ++ h_parent = d_find_any_alias(h_dir); ++ if (unlikely(!h_parent)) ++ goto out_hparent; ++ ++ err = -EPERM; ++ br = au_sbr(sb, bindex); ++ h_sb = au_br_sb(br); ++ if (unlikely(!h_sb->s_export_op)) { ++ AuErr1("%s branch is not exportable\n", au_sbtype(h_sb)); ++ goto out_hparent; ++ } ++ ++ fh[Fh_br_id] = br->br_id; ++ fh[Fh_sigen] = au_sigen(sb); ++ encode_ino(fh + Fh_ino, inode->i_ino); ++ encode_ino(fh + Fh_dir_ino, dir->i_ino); ++ fh[Fh_igen] = inode->i_generation; ++ ++ *max_len -= Fh_tail; ++ fh[Fh_h_type] = exportfs_encode_fh(h_parent, (void *)(fh + Fh_tail), ++ max_len, ++ /*connectable or subtreecheck*/0); ++ err = fh[Fh_h_type]; ++ *max_len += Fh_tail; ++ /* todo: macros? */ ++ if (err != FILEID_INVALID) ++ err = 99; ++ else ++ AuWarn1("%s encode_fh failed\n", au_sbtype(h_sb)); ++ ++out_hparent: ++ dput(h_parent); ++out_parent: ++ dput(parent); ++out_unlock: ++ ii_read_unlock(inode); ++ si_read_unlock(sb); ++out: ++ if (unlikely(err < 0)) ++ err = FILEID_INVALID; ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_commit_metadata(struct inode *inode) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct super_block *sb; ++ struct inode *h_inode; ++ int (*f)(struct inode *inode); ++ ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ii_write_lock_child(inode); ++ bindex = au_ibtop(inode); ++ AuDebugOn(bindex < 0); ++ h_inode = au_h_iptr(inode, bindex); ++ ++ f = h_inode->i_sb->s_export_op->commit_metadata; ++ if (f) ++ err = f(h_inode); ++ else ++ err = sync_inode_metadata(h_inode, /*wait*/1); ++ ++ au_cpup_attr_timesizes(inode); ++ ii_write_unlock(inode); ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct export_operations aufs_export_op = { ++ .fh_to_dentry = aufs_fh_to_dentry, ++ /* .fh_to_parent = aufs_fh_to_parent, */ ++ .encode_fh = aufs_encode_fh, ++ .commit_metadata = aufs_commit_metadata ++}; ++ ++void au_export_init(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ __u32 u; ++ ++ BUILD_BUG_ON_MSG(IS_BUILTIN(CONFIG_AUFS_FS) ++ && IS_MODULE(CONFIG_EXPORTFS), ++ AUFS_NAME ": unsupported configuration " ++ "CONFIG_EXPORTFS=m and CONFIG_AUFS_FS=y"); ++ ++ sb->s_export_op = &aufs_export_op; ++ sbinfo = au_sbi(sb); ++ sbinfo->si_xigen = NULL; ++ get_random_bytes(&u, sizeof(u)); ++ BUILD_BUG_ON(sizeof(u) != sizeof(int)); ++ atomic_set(&sbinfo->si_xigen_next, u); ++} +diff -Naur null/fs/aufs/fhsm.c linux-5.15.36/fs/aufs/fhsm.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/fhsm.c 2022-05-10 16:51:39.870744219 +0300 +@@ -0,0 +1,427 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2011-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * File-based Hierarchy Storage Management ++ */ ++ ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++static aufs_bindex_t au_fhsm_bottom(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ AuDebugOn(!fhsm); ++ return fhsm->fhsm_bottom; ++} ++ ++void au_fhsm_set_bottom(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ AuDebugOn(!fhsm); ++ fhsm->fhsm_bottom = bindex; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_fhsm_test_jiffy(struct au_sbinfo *sbinfo, struct au_branch *br) ++{ ++ struct au_br_fhsm *bf; ++ ++ bf = br->br_fhsm; ++ MtxMustLock(&bf->bf_lock); ++ ++ return !bf->bf_readable ++ || time_after(jiffies, ++ bf->bf_jiffy + sbinfo->si_fhsm.fhsm_expire); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_fhsm_notify(struct super_block *sb, int val) ++{ ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ if (au_fhsm_pid(fhsm) ++ && atomic_read(&fhsm->fhsm_readable) != -1) { ++ atomic_set(&fhsm->fhsm_readable, val); ++ if (val) ++ wake_up(&fhsm->fhsm_wqh); ++ } ++} ++ ++static int au_fhsm_stfs(struct super_block *sb, aufs_bindex_t bindex, ++ struct aufs_stfs *rstfs, int do_lock, int do_notify) ++{ ++ int err; ++ struct au_branch *br; ++ struct au_br_fhsm *bf; ++ ++ br = au_sbr(sb, bindex); ++ AuDebugOn(au_br_rdonly(br)); ++ bf = br->br_fhsm; ++ AuDebugOn(!bf); ++ ++ if (do_lock) ++ mutex_lock(&bf->bf_lock); ++ else ++ MtxMustLock(&bf->bf_lock); ++ ++ /* sb->s_root for NFS is unreliable */ ++ err = au_br_stfs(br, &bf->bf_stfs); ++ if (unlikely(err)) { ++ AuErr1("FHSM failed (%d), b%d, ignored.\n", bindex, err); ++ goto out; ++ } ++ ++ bf->bf_jiffy = jiffies; ++ bf->bf_readable = 1; ++ if (do_notify) ++ au_fhsm_notify(sb, /*val*/1); ++ if (rstfs) ++ *rstfs = bf->bf_stfs; ++ ++out: ++ if (do_lock) ++ mutex_unlock(&bf->bf_lock); ++ au_fhsm_notify(sb, /*val*/1); ++ ++ return err; ++} ++ ++void au_fhsm_wrote(struct super_block *sb, aufs_bindex_t bindex, int force) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ struct au_branch *br; ++ struct au_br_fhsm *bf; ++ ++ AuDbg("b%d, force %d\n", bindex, force); ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ if (!au_ftest_si(sbinfo, FHSM) ++ || fhsm->fhsm_bottom == bindex) ++ return; ++ ++ br = au_sbr(sb, bindex); ++ bf = br->br_fhsm; ++ AuDebugOn(!bf); ++ mutex_lock(&bf->bf_lock); ++ if (force ++ || au_fhsm_pid(fhsm) ++ || au_fhsm_test_jiffy(sbinfo, br)) ++ err = au_fhsm_stfs(sb, bindex, /*rstfs*/NULL, /*do_lock*/0, ++ /*do_notify*/1); ++ mutex_unlock(&bf->bf_lock); ++} ++ ++void au_fhsm_wrote_all(struct super_block *sb, int force) ++{ ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ /* exclude the bottom */ ++ bbot = au_fhsm_bottom(sb); ++ for (bindex = 0; bindex < bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm)) ++ au_fhsm_wrote(sb, bindex, force); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static __poll_t au_fhsm_poll(struct file *file, struct poll_table_struct *wait) ++{ ++ __poll_t mask; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ mask = 0; ++ sbinfo = file->private_data; ++ fhsm = &sbinfo->si_fhsm; ++ poll_wait(file, &fhsm->fhsm_wqh, wait); ++ if (atomic_read(&fhsm->fhsm_readable)) ++ mask = EPOLLIN /* | EPOLLRDNORM */; ++ ++ if (!mask) ++ AuDbg("mask 0x%x\n", mask); ++ return mask; ++} ++ ++static int au_fhsm_do_read_one(struct aufs_stbr __user *stbr, ++ struct aufs_stfs *stfs, __s16 brid) ++{ ++ int err; ++ ++ err = copy_to_user(&stbr->stfs, stfs, sizeof(*stfs)); ++ if (!err) ++ err = __put_user(brid, &stbr->brid); ++ if (unlikely(err)) ++ err = -EFAULT; ++ ++ return err; ++} ++ ++static ssize_t au_fhsm_do_read(struct super_block *sb, ++ struct aufs_stbr __user *stbr, size_t count) ++{ ++ ssize_t err; ++ int nstbr; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ struct au_br_fhsm *bf; ++ ++ /* except the bottom branch */ ++ err = 0; ++ nstbr = 0; ++ bbot = au_fhsm_bottom(sb); ++ for (bindex = 0; !err && bindex < bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!au_br_fhsm(br->br_perm)) ++ continue; ++ ++ bf = br->br_fhsm; ++ mutex_lock(&bf->bf_lock); ++ if (bf->bf_readable) { ++ err = -EFAULT; ++ if (count >= sizeof(*stbr)) ++ err = au_fhsm_do_read_one(stbr++, &bf->bf_stfs, ++ br->br_id); ++ if (!err) { ++ bf->bf_readable = 0; ++ count -= sizeof(*stbr); ++ nstbr++; ++ } ++ } ++ mutex_unlock(&bf->bf_lock); ++ } ++ if (!err) ++ err = sizeof(*stbr) * nstbr; ++ ++ return err; ++} ++ ++static ssize_t au_fhsm_read(struct file *file, char __user *buf, size_t count, ++ loff_t *pos) ++{ ++ ssize_t err; ++ int readable; ++ aufs_bindex_t nfhsm, bindex, bbot; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ struct au_branch *br; ++ struct super_block *sb; ++ ++ err = 0; ++ sbinfo = file->private_data; ++ fhsm = &sbinfo->si_fhsm; ++need_data: ++ spin_lock_irq(&fhsm->fhsm_wqh.lock); ++ if (!atomic_read(&fhsm->fhsm_readable)) { ++ if (vfsub_file_flags(file) & O_NONBLOCK) ++ err = -EAGAIN; ++ else ++ err = wait_event_interruptible_locked_irq ++ (fhsm->fhsm_wqh, ++ atomic_read(&fhsm->fhsm_readable)); ++ } ++ spin_unlock_irq(&fhsm->fhsm_wqh.lock); ++ if (unlikely(err)) ++ goto out; ++ ++ /* sb may already be dead */ ++ au_rw_read_lock(&sbinfo->si_rwsem); ++ readable = atomic_read(&fhsm->fhsm_readable); ++ if (readable > 0) { ++ sb = sbinfo->si_sb; ++ AuDebugOn(!sb); ++ /* exclude the bottom branch */ ++ nfhsm = 0; ++ bbot = au_fhsm_bottom(sb); ++ for (bindex = 0; bindex < bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm)) ++ nfhsm++; ++ } ++ err = -EMSGSIZE; ++ if (nfhsm * sizeof(struct aufs_stbr) <= count) { ++ atomic_set(&fhsm->fhsm_readable, 0); ++ err = au_fhsm_do_read(sbinfo->si_sb, (void __user *)buf, ++ count); ++ } ++ } ++ au_rw_read_unlock(&sbinfo->si_rwsem); ++ if (!readable) ++ goto need_data; ++ ++out: ++ return err; ++} ++ ++static int au_fhsm_release(struct inode *inode, struct file *file) ++{ ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ /* sb may already be dead */ ++ sbinfo = file->private_data; ++ fhsm = &sbinfo->si_fhsm; ++ spin_lock(&fhsm->fhsm_spin); ++ fhsm->fhsm_pid = 0; ++ spin_unlock(&fhsm->fhsm_spin); ++ kobject_put(&sbinfo->si_kobj); ++ ++ return 0; ++} ++ ++static const struct file_operations au_fhsm_fops = { ++ .owner = THIS_MODULE, ++ .llseek = noop_llseek, ++ .read = au_fhsm_read, ++ .poll = au_fhsm_poll, ++ .release = au_fhsm_release ++}; ++ ++int au_fhsm_fd(struct super_block *sb, int oflags) ++{ ++ int err, fd; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ err = -EPERM; ++ if (unlikely(!capable(CAP_SYS_ADMIN))) ++ goto out; ++ ++ err = -EINVAL; ++ if (unlikely(oflags & ~(O_CLOEXEC | O_NONBLOCK))) ++ goto out; ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ spin_lock(&fhsm->fhsm_spin); ++ if (!fhsm->fhsm_pid) ++ fhsm->fhsm_pid = current->pid; ++ else ++ err = -EBUSY; ++ spin_unlock(&fhsm->fhsm_spin); ++ if (unlikely(err)) ++ goto out; ++ ++ oflags |= O_RDONLY; ++ /* oflags |= FMODE_NONOTIFY; */ ++ fd = anon_inode_getfd("[aufs_fhsm]", &au_fhsm_fops, sbinfo, oflags); ++ err = fd; ++ if (unlikely(fd < 0)) ++ goto out_pid; ++ ++ /* succeed regardless 'fhsm' status */ ++ kobject_get(&sbinfo->si_kobj); ++ si_noflush_read_lock(sb); ++ if (au_ftest_si(sbinfo, FHSM)) ++ au_fhsm_wrote_all(sb, /*force*/0); ++ si_read_unlock(sb); ++ goto out; /* success */ ++ ++out_pid: ++ spin_lock(&fhsm->fhsm_spin); ++ fhsm->fhsm_pid = 0; ++ spin_unlock(&fhsm->fhsm_spin); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_fhsm_br_alloc(struct au_branch *br) ++{ ++ int err; ++ ++ err = 0; ++ br->br_fhsm = kmalloc(sizeof(*br->br_fhsm), GFP_NOFS); ++ if (br->br_fhsm) ++ au_br_fhsm_init(br->br_fhsm); ++ else ++ err = -ENOMEM; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_fhsm_fin(struct super_block *sb) ++{ ++ au_fhsm_notify(sb, /*val*/-1); ++} ++ ++void au_fhsm_init(struct au_sbinfo *sbinfo) ++{ ++ struct au_fhsm *fhsm; ++ ++ fhsm = &sbinfo->si_fhsm; ++ spin_lock_init(&fhsm->fhsm_spin); ++ init_waitqueue_head(&fhsm->fhsm_wqh); ++ atomic_set(&fhsm->fhsm_readable, 0); ++ fhsm->fhsm_expire ++ = msecs_to_jiffies(AUFS_FHSM_CACHE_DEF_SEC * MSEC_PER_SEC); ++ fhsm->fhsm_bottom = -1; ++} ++ ++void au_fhsm_set(struct au_sbinfo *sbinfo, unsigned int sec) ++{ ++ sbinfo->si_fhsm.fhsm_expire ++ = msecs_to_jiffies(sec * MSEC_PER_SEC); ++} ++ ++void au_fhsm_show(struct seq_file *seq, struct au_sbinfo *sbinfo) ++{ ++ unsigned int u; ++ ++ if (!au_ftest_si(sbinfo, FHSM)) ++ return; ++ ++ u = jiffies_to_msecs(sbinfo->si_fhsm.fhsm_expire) / MSEC_PER_SEC; ++ if (u != AUFS_FHSM_CACHE_DEF_SEC) ++ seq_printf(seq, ",fhsm_sec=%u", u); ++} +diff -Naur null/fs/aufs/file.c linux-5.15.36/fs/aufs/file.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/file.c 2022-05-10 16:51:39.870744219 +0300 +@@ -0,0 +1,863 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * handling file/dir, and address_space operation ++ */ ++ ++#ifdef CONFIG_AUFS_DEBUG ++#include ++#endif ++#include ++#include "aufs.h" ++ ++/* drop flags for writing */ ++unsigned int au_file_roflags(unsigned int flags) ++{ ++ flags &= ~(O_WRONLY | O_RDWR | O_APPEND | O_CREAT | O_TRUNC); ++ flags |= O_RDONLY | O_NOATIME; ++ return flags; ++} ++ ++/* common functions to regular file and dir */ ++struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, ++ struct file *file, int force_wr) ++{ ++ struct file *h_file; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct path h_path; ++ int err; ++ ++ /* a race condition can happen between open and unlink/rmdir */ ++ h_file = ERR_PTR(-ENOENT); ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (au_test_nfsd() && (!h_dentry || d_is_negative(h_dentry))) ++ goto out; ++ h_inode = d_inode(h_dentry); ++ spin_lock(&h_dentry->d_lock); ++ err = (!d_unhashed(dentry) && d_unlinked(h_dentry)) ++ /* || !d_inode(dentry)->i_nlink */ ++ ; ++ spin_unlock(&h_dentry->d_lock); ++ if (unlikely(err)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, bindex); ++ err = au_br_test_oflag(flags, br); ++ h_file = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ /* drop flags for writing */ ++ if (au_test_ro(sb, bindex, d_inode(dentry))) { ++ if (force_wr && !(flags & O_WRONLY)) ++ force_wr = 0; ++ flags = au_file_roflags(flags); ++ if (force_wr) { ++ h_file = ERR_PTR(-EROFS); ++ flags = au_file_roflags(flags); ++ if (unlikely(vfsub_native_ro(h_inode) ++ || IS_APPEND(h_inode))) ++ goto out; ++ flags &= ~O_ACCMODE; ++ flags |= O_WRONLY; ++ } ++ } ++ flags &= ~O_CREAT; ++ au_lcnt_inc(&br->br_nfiles); ++ h_path.dentry = h_dentry; ++ h_path.mnt = au_br_mnt(br); ++ h_file = vfsub_dentry_open(&h_path, flags); ++ if (IS_ERR(h_file)) ++ goto out_br; ++ ++ if (flags & __FMODE_EXEC) { ++ err = deny_write_access(h_file); ++ if (unlikely(err)) { ++ fput(h_file); ++ h_file = ERR_PTR(err); ++ goto out_br; ++ } ++ } ++ fsnotify_open(h_file); ++ goto out; /* success */ ++ ++out_br: ++ au_lcnt_dec(&br->br_nfiles); ++out: ++ return h_file; ++} ++ ++static int au_cmoo(struct dentry *dentry) ++{ ++ int err, cmoo, matched; ++ unsigned int udba; ++ struct path h_path; ++ struct au_pin pin; ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = -1, ++ .bsrc = -1, ++ .len = -1, ++ .pin = &pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ struct inode *delegated; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ pid_t pid; ++ struct au_branch *br; ++ struct dentry *parent; ++ struct au_hinode *hdir; ++ ++ DiMustWriteLock(dentry); ++ IiMustWriteLock(d_inode(dentry)); ++ ++ err = 0; ++ if (IS_ROOT(dentry)) ++ goto out; ++ cpg.bsrc = au_dbtop(dentry); ++ if (!cpg.bsrc) ++ goto out; ++ ++ sb = dentry->d_sb; ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ pid = au_fhsm_pid(fhsm); ++ rcu_read_lock(); ++ matched = (pid ++ && (current->pid == pid ++ || rcu_dereference(current->real_parent)->pid == pid)); ++ rcu_read_unlock(); ++ if (matched) ++ goto out; ++ ++ br = au_sbr(sb, cpg.bsrc); ++ cmoo = au_br_cmoo(br->br_perm); ++ if (!cmoo) ++ goto out; ++ if (!d_is_reg(dentry)) ++ cmoo &= AuBrAttr_COO_ALL; ++ if (!cmoo) ++ goto out; ++ ++ parent = dget_parent(dentry); ++ di_write_lock_parent(parent); ++ err = au_wbr_do_copyup_bu(dentry, cpg.bsrc - 1); ++ cpg.bdst = err; ++ if (unlikely(err < 0)) { ++ err = 0; /* there is no upper writable branch */ ++ goto out_dgrade; ++ } ++ AuDbg("bsrc %d, bdst %d\n", cpg.bsrc, cpg.bdst); ++ ++ /* do not respect the coo attrib for the target branch */ ++ err = au_cpup_dirs(dentry, cpg.bdst); ++ if (unlikely(err)) ++ goto out_dgrade; ++ ++ di_downgrade_lock(parent, AuLock_IR); ++ udba = au_opt_udba(sb); ++ err = au_pin(&pin, dentry, cpg.bdst, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&pin); ++ if (unlikely(err)) ++ goto out_parent; ++ if (!(cmoo & AuBrWAttr_MOO)) ++ goto out_parent; /* success */ ++ ++ err = au_pin(&pin, dentry, cpg.bsrc, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ h_path.mnt = au_br_mnt(br); ++ h_path.dentry = au_h_dptr(dentry, cpg.bsrc); ++ hdir = au_hi(d_inode(parent), cpg.bsrc); ++ delegated = NULL; ++ err = vfsub_unlink(hdir->hi_inode, &h_path, &delegated, /*force*/1); ++ au_unpin(&pin); ++ /* todo: keep h_dentry or not? */ ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ if (unlikely(err)) { ++ pr_err("unlink %pd after coo failed (%d), ignored\n", ++ dentry, err); ++ err = 0; ++ } ++ goto out_parent; /* success */ ++ ++out_dgrade: ++ di_downgrade_lock(parent, AuLock_IR); ++out_parent: ++ di_read_unlock(parent, AuLock_IR); ++ dput(parent); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_do_open(struct file *file, struct au_do_open_args *args) ++{ ++ int err, aopen = args->aopen; ++ struct dentry *dentry; ++ struct au_finfo *finfo; ++ ++ if (!aopen) ++ err = au_finfo_init(file, args->fidir); ++ else { ++ lockdep_off(); ++ err = au_finfo_init(file, args->fidir); ++ lockdep_on(); ++ } ++ if (unlikely(err)) ++ goto out; ++ ++ dentry = file->f_path.dentry; ++ AuDebugOn(IS_ERR_OR_NULL(dentry)); ++ di_write_lock_child(dentry); ++ err = au_cmoo(dentry); ++ di_downgrade_lock(dentry, AuLock_IR); ++ if (!err) { ++ if (!aopen) ++ err = args->open(file, vfsub_file_flags(file), NULL); ++ else { ++ lockdep_off(); ++ err = args->open(file, vfsub_file_flags(file), ++ args->h_file); ++ lockdep_on(); ++ } ++ } ++ di_read_unlock(dentry, AuLock_IR); ++ ++ finfo = au_fi(file); ++ if (!err) { ++ finfo->fi_file = file; ++ au_hbl_add(&finfo->fi_hlist, ++ &au_sbi(file->f_path.dentry->d_sb)->si_files); ++ } ++ if (!aopen) ++ fi_write_unlock(file); ++ else { ++ lockdep_off(); ++ fi_write_unlock(file); ++ lockdep_on(); ++ } ++ if (unlikely(err)) { ++ finfo->fi_hdir = NULL; ++ au_finfo_fin(file); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_reopen_nondir(struct file *file) ++{ ++ int err; ++ aufs_bindex_t btop; ++ struct dentry *dentry; ++ struct au_branch *br; ++ struct file *h_file, *h_file_tmp; ++ ++ dentry = file->f_path.dentry; ++ btop = au_dbtop(dentry); ++ br = au_sbr(dentry->d_sb, btop); ++ h_file_tmp = NULL; ++ if (au_fbtop(file) == btop) { ++ h_file = au_hf_top(file); ++ if (file->f_mode == h_file->f_mode) ++ return 0; /* success */ ++ h_file_tmp = h_file; ++ get_file(h_file_tmp); ++ au_lcnt_inc(&br->br_nfiles); ++ au_set_h_fptr(file, btop, NULL); ++ } ++ AuDebugOn(au_fi(file)->fi_hdir); ++ /* ++ * it can happen ++ * file exists on both of rw and ro ++ * open --> dbtop and fbtop are both 0 ++ * prepend a branch as rw, "rw" become ro ++ * remove rw/file ++ * delete the top branch, "rw" becomes rw again ++ * --> dbtop is 1, fbtop is still 0 ++ * write --> fbtop is 0 but dbtop is 1 ++ */ ++ /* AuDebugOn(au_fbtop(file) < btop); */ ++ ++ h_file = au_h_open(dentry, btop, vfsub_file_flags(file) & ~O_TRUNC, ++ file, /*force_wr*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) { ++ if (h_file_tmp) { ++ /* revert */ ++ au_set_h_fptr(file, btop, h_file_tmp); ++ h_file_tmp = NULL; ++ } ++ goto out; /* todo: close all? */ ++ } ++ ++ err = 0; ++ au_set_fbtop(file, btop); ++ au_set_h_fptr(file, btop, h_file); ++ au_update_figen(file); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ ++out: ++ if (h_file_tmp) { ++ fput(h_file_tmp); ++ au_lcnt_dec(&br->br_nfiles); ++ } ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_reopen_wh(struct file *file, aufs_bindex_t btgt, ++ struct dentry *hi_wh) ++{ ++ int err; ++ aufs_bindex_t btop; ++ struct au_dinfo *dinfo; ++ struct dentry *h_dentry; ++ struct au_hdentry *hdp; ++ ++ dinfo = au_di(file->f_path.dentry); ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ btop = dinfo->di_btop; ++ dinfo->di_btop = btgt; ++ hdp = au_hdentry(dinfo, btgt); ++ h_dentry = hdp->hd_dentry; ++ hdp->hd_dentry = hi_wh; ++ err = au_reopen_nondir(file); ++ hdp->hd_dentry = h_dentry; ++ dinfo->di_btop = btop; ++ ++ return err; ++} ++ ++static int au_ready_to_write_wh(struct file *file, loff_t len, ++ aufs_bindex_t bcpup, struct au_pin *pin) ++{ ++ int err; ++ struct inode *inode, *h_inode; ++ struct dentry *h_dentry, *hi_wh; ++ struct au_cp_generic cpg = { ++ .dentry = file->f_path.dentry, ++ .bdst = bcpup, ++ .bsrc = -1, ++ .len = len, ++ .pin = pin ++ }; ++ ++ au_update_dbtop(cpg.dentry); ++ inode = d_inode(cpg.dentry); ++ h_inode = NULL; ++ if (au_dbtop(cpg.dentry) <= bcpup ++ && au_dbbot(cpg.dentry) >= bcpup) { ++ h_dentry = au_h_dptr(cpg.dentry, bcpup); ++ if (h_dentry && d_is_positive(h_dentry)) ++ h_inode = d_inode(h_dentry); ++ } ++ hi_wh = au_hi_wh(inode, bcpup); ++ if (!hi_wh && !h_inode) ++ err = au_sio_cpup_wh(&cpg, file); ++ else ++ /* already copied-up after unlink */ ++ err = au_reopen_wh(file, bcpup, hi_wh); ++ ++ if (!err ++ && (inode->i_nlink > 1 ++ || (inode->i_state & I_LINKABLE)) ++ && au_opt_test(au_mntflags(cpg.dentry->d_sb), PLINK)) ++ au_plink_append(inode, bcpup, au_h_dptr(cpg.dentry, bcpup)); ++ ++ return err; ++} ++ ++/* ++ * prepare the @file for writing. ++ */ ++int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin) ++{ ++ int err; ++ aufs_bindex_t dbtop; ++ struct dentry *parent; ++ struct inode *inode; ++ struct super_block *sb; ++ struct file *h_file; ++ struct au_cp_generic cpg = { ++ .dentry = file->f_path.dentry, ++ .bdst = -1, ++ .bsrc = -1, ++ .len = len, ++ .pin = pin, ++ .flags = AuCpup_DTIME ++ }; ++ ++ sb = cpg.dentry->d_sb; ++ inode = d_inode(cpg.dentry); ++ cpg.bsrc = au_fbtop(file); ++ err = au_test_ro(sb, cpg.bsrc, inode); ++ if (!err && (au_hf_top(file)->f_mode & FMODE_WRITE)) { ++ err = au_pin(pin, cpg.dentry, cpg.bsrc, AuOpt_UDBA_NONE, ++ /*flags*/0); ++ goto out; ++ } ++ ++ /* need to cpup or reopen */ ++ parent = dget_parent(cpg.dentry); ++ di_write_lock_parent(parent); ++ err = AuWbrCopyup(au_sbi(sb), cpg.dentry); ++ cpg.bdst = err; ++ if (unlikely(err < 0)) ++ goto out_dgrade; ++ err = 0; ++ ++ if (!d_unhashed(cpg.dentry) && !au_h_dptr(parent, cpg.bdst)) { ++ err = au_cpup_dirs(cpg.dentry, cpg.bdst); ++ if (unlikely(err)) ++ goto out_dgrade; ++ } ++ ++ err = au_pin(pin, cpg.dentry, cpg.bdst, AuOpt_UDBA_NONE, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_dgrade; ++ ++ dbtop = au_dbtop(cpg.dentry); ++ if (dbtop <= cpg.bdst) ++ cpg.bsrc = cpg.bdst; ++ ++ if (dbtop <= cpg.bdst /* just reopen */ ++ || !d_unhashed(cpg.dentry) /* copyup and reopen */ ++ ) { ++ h_file = au_h_open_pre(cpg.dentry, cpg.bsrc, /*force_wr*/0); ++ if (IS_ERR(h_file)) ++ err = PTR_ERR(h_file); ++ else { ++ di_downgrade_lock(parent, AuLock_IR); ++ if (dbtop > cpg.bdst) ++ err = au_sio_cpup_simple(&cpg); ++ if (!err) ++ err = au_reopen_nondir(file); ++ au_h_open_post(cpg.dentry, cpg.bsrc, h_file); ++ } ++ } else { /* copyup as wh and reopen */ ++ /* ++ * since writable hfsplus branch is not supported, ++ * h_open_pre/post() are unnecessary. ++ */ ++ err = au_ready_to_write_wh(file, len, cpg.bdst, pin); ++ di_downgrade_lock(parent, AuLock_IR); ++ } ++ ++ if (!err) { ++ au_pin_set_parent_lflag(pin, /*lflag*/0); ++ goto out_dput; /* success */ ++ } ++ au_unpin(pin); ++ goto out_unlock; ++ ++out_dgrade: ++ di_downgrade_lock(parent, AuLock_IR); ++out_unlock: ++ di_read_unlock(parent, AuLock_IR); ++out_dput: ++ dput(parent); ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_do_flush(struct file *file, fl_owner_t id, ++ int (*flush)(struct file *file, fl_owner_t id)) ++{ ++ int err; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ si_noflush_read_lock(sb); ++ fi_read_lock(file); ++ ii_read_lock_child(inode); ++ ++ err = flush(file, id); ++ au_cpup_attr_timesizes(inode); ++ ++ ii_read_unlock(inode); ++ fi_read_unlock(file); ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_file_refresh_by_inode(struct file *file, int *need_reopen) ++{ ++ int err; ++ struct au_pin pin; ++ struct au_finfo *finfo; ++ struct dentry *parent, *hi_wh; ++ struct inode *inode; ++ struct super_block *sb; ++ struct au_cp_generic cpg = { ++ .dentry = file->f_path.dentry, ++ .bdst = -1, ++ .bsrc = -1, ++ .len = -1, ++ .pin = &pin, ++ .flags = AuCpup_DTIME ++ }; ++ ++ FiMustWriteLock(file); ++ ++ err = 0; ++ finfo = au_fi(file); ++ sb = cpg.dentry->d_sb; ++ inode = d_inode(cpg.dentry); ++ cpg.bdst = au_ibtop(inode); ++ if (cpg.bdst == finfo->fi_btop || IS_ROOT(cpg.dentry)) ++ goto out; ++ ++ parent = dget_parent(cpg.dentry); ++ if (au_test_ro(sb, cpg.bdst, inode)) { ++ di_read_lock_parent(parent, !AuLock_IR); ++ err = AuWbrCopyup(au_sbi(sb), cpg.dentry); ++ cpg.bdst = err; ++ di_read_unlock(parent, !AuLock_IR); ++ if (unlikely(err < 0)) ++ goto out_parent; ++ err = 0; ++ } ++ ++ di_read_lock_parent(parent, AuLock_IR); ++ hi_wh = au_hi_wh(inode, cpg.bdst); ++ if (!S_ISDIR(inode->i_mode) ++ && au_opt_test(au_mntflags(sb), PLINK) ++ && au_plink_test(inode) ++ && !d_unhashed(cpg.dentry) ++ && cpg.bdst < au_dbtop(cpg.dentry)) { ++ err = au_test_and_cpup_dirs(cpg.dentry, cpg.bdst); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ /* always superio. */ ++ err = au_pin(&pin, cpg.dentry, cpg.bdst, AuOpt_UDBA_NONE, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (!err) { ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&pin); ++ } ++ } else if (hi_wh) { ++ /* already copied-up after unlink */ ++ err = au_reopen_wh(file, cpg.bdst, hi_wh); ++ *need_reopen = 0; ++ } ++ ++out_unlock: ++ di_read_unlock(parent, AuLock_IR); ++out_parent: ++ dput(parent); ++out: ++ return err; ++} ++ ++static void au_do_refresh_dir(struct file *file) ++{ ++ aufs_bindex_t bindex, bbot, new_bindex, brid; ++ struct au_hfile *p, tmp, *q; ++ struct au_finfo *finfo; ++ struct super_block *sb; ++ struct au_fidir *fidir; ++ ++ FiMustWriteLock(file); ++ ++ sb = file->f_path.dentry->d_sb; ++ finfo = au_fi(file); ++ fidir = finfo->fi_hdir; ++ AuDebugOn(!fidir); ++ p = fidir->fd_hfile + finfo->fi_btop; ++ brid = p->hf_br->br_id; ++ bbot = fidir->fd_bbot; ++ for (bindex = finfo->fi_btop; bindex <= bbot; bindex++, p++) { ++ if (!p->hf_file) ++ continue; ++ ++ new_bindex = au_br_index(sb, p->hf_br->br_id); ++ if (new_bindex == bindex) ++ continue; ++ if (new_bindex < 0) { ++ au_set_h_fptr(file, bindex, NULL); ++ continue; ++ } ++ ++ /* swap two lower inode, and loop again */ ++ q = fidir->fd_hfile + new_bindex; ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hf_file) { ++ bindex--; ++ p--; ++ } ++ } ++ ++ p = fidir->fd_hfile; ++ if (!au_test_mmapped(file) && !d_unlinked(file->f_path.dentry)) { ++ bbot = au_sbbot(sb); ++ for (finfo->fi_btop = 0; finfo->fi_btop <= bbot; ++ finfo->fi_btop++, p++) ++ if (p->hf_file) { ++ if (file_inode(p->hf_file)) ++ break; ++ au_hfput(p, /*execed*/0); ++ } ++ } else { ++ bbot = au_br_index(sb, brid); ++ for (finfo->fi_btop = 0; finfo->fi_btop < bbot; ++ finfo->fi_btop++, p++) ++ if (p->hf_file) ++ au_hfput(p, /*execed*/0); ++ bbot = au_sbbot(sb); ++ } ++ ++ p = fidir->fd_hfile + bbot; ++ for (fidir->fd_bbot = bbot; fidir->fd_bbot >= finfo->fi_btop; ++ fidir->fd_bbot--, p--) ++ if (p->hf_file) { ++ if (file_inode(p->hf_file)) ++ break; ++ au_hfput(p, /*execed*/0); ++ } ++ AuDebugOn(fidir->fd_bbot < finfo->fi_btop); ++} ++ ++/* ++ * after branch manipulating, refresh the file. ++ */ ++static int refresh_file(struct file *file, int (*reopen)(struct file *file)) ++{ ++ int err, need_reopen, nbr; ++ aufs_bindex_t bbot, bindex; ++ struct dentry *dentry; ++ struct super_block *sb; ++ struct au_finfo *finfo; ++ struct au_hfile *hfile; ++ ++ dentry = file->f_path.dentry; ++ sb = dentry->d_sb; ++ nbr = au_sbbot(sb) + 1; ++ finfo = au_fi(file); ++ if (!finfo->fi_hdir) { ++ hfile = &finfo->fi_htop; ++ AuDebugOn(!hfile->hf_file); ++ bindex = au_br_index(sb, hfile->hf_br->br_id); ++ AuDebugOn(bindex < 0); ++ if (bindex != finfo->fi_btop) ++ au_set_fbtop(file, bindex); ++ } else { ++ err = au_fidir_realloc(finfo, nbr, /*may_shrink*/0); ++ if (unlikely(err)) ++ goto out; ++ au_do_refresh_dir(file); ++ } ++ ++ err = 0; ++ need_reopen = 1; ++ if (!au_test_mmapped(file)) ++ err = au_file_refresh_by_inode(file, &need_reopen); ++ if (finfo->fi_hdir) ++ /* harmless if err */ ++ au_fidir_realloc(finfo, nbr, /*may_shrink*/1); ++ if (!err && need_reopen && !d_unlinked(dentry)) ++ err = reopen(file); ++ if (!err) { ++ au_update_figen(file); ++ goto out; /* success */ ++ } ++ ++ /* error, close all lower files */ ++ if (finfo->fi_hdir) { ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); bindex <= bbot; bindex++) ++ au_set_h_fptr(file, bindex, NULL); ++ } ++ ++out: ++ return err; ++} ++ ++/* common function to regular file and dir */ ++int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file), ++ int wlock, unsigned int fi_lsc) ++{ ++ int err; ++ unsigned int sigen, figen; ++ aufs_bindex_t btop; ++ unsigned char pseudo_link; ++ struct dentry *dentry; ++ struct inode *inode; ++ ++ err = 0; ++ dentry = file->f_path.dentry; ++ inode = d_inode(dentry); ++ sigen = au_sigen(dentry->d_sb); ++ fi_write_lock_nested(file, fi_lsc); ++ figen = au_figen(file); ++ if (!fi_lsc) ++ di_write_lock_child(dentry); ++ else ++ di_write_lock_child2(dentry); ++ btop = au_dbtop(dentry); ++ pseudo_link = (btop != au_ibtop(inode)); ++ if (sigen == figen && !pseudo_link && au_fbtop(file) == btop) { ++ if (!wlock) { ++ di_downgrade_lock(dentry, AuLock_IR); ++ fi_downgrade_lock(file); ++ } ++ goto out; /* success */ ++ } ++ ++ AuDbg("sigen %d, figen %d\n", sigen, figen); ++ if (au_digen_test(dentry, sigen)) { ++ err = au_reval_dpath(dentry, sigen); ++ AuDebugOn(!err && au_digen_test(dentry, sigen)); ++ } ++ ++ if (!err) ++ err = refresh_file(file, reopen); ++ if (!err) { ++ if (!wlock) { ++ di_downgrade_lock(dentry, AuLock_IR); ++ fi_downgrade_lock(file); ++ } ++ } else { ++ di_write_unlock(dentry); ++ fi_write_unlock(file); ++ } ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* cf. aufs_nopage() */ ++/* for madvise(2) */ ++static int aufs_readpage(struct file *file __maybe_unused, struct page *page) ++{ ++ unlock_page(page); ++ return 0; ++} ++ ++/* it will never be called, but necessary to support O_DIRECT */ ++static ssize_t aufs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) ++{ BUG(); return 0; } ++ ++/* they will never be called. */ ++#ifdef CONFIG_AUFS_DEBUG ++static int aufs_write_begin(struct file *file, struct address_space *mapping, ++ loff_t pos, unsigned len, unsigned flags, ++ struct page **pagep, void **fsdata) ++{ AuUnsupport(); return 0; } ++static int aufs_write_end(struct file *file, struct address_space *mapping, ++ loff_t pos, unsigned len, unsigned copied, ++ struct page *page, void *fsdata) ++{ AuUnsupport(); return 0; } ++static int aufs_writepage(struct page *page, struct writeback_control *wbc) ++{ AuUnsupport(); return 0; } ++ ++static int aufs_set_page_dirty(struct page *page) ++{ AuUnsupport(); return 0; } ++static void aufs_invalidatepage(struct page *page, unsigned int offset, ++ unsigned int length) ++{ AuUnsupport(); } ++static int aufs_releasepage(struct page *page, gfp_t gfp) ++{ AuUnsupport(); return 0; } ++#if 0 /* called by memory compaction regardless file */ ++static int aufs_migratepage(struct address_space *mapping, struct page *newpage, ++ struct page *page, enum migrate_mode mode) ++{ AuUnsupport(); return 0; } ++#endif ++static bool aufs_isolate_page(struct page *page, isolate_mode_t mode) ++{ AuUnsupport(); return true; } ++static void aufs_putback_page(struct page *page) ++{ AuUnsupport(); } ++static int aufs_launder_page(struct page *page) ++{ AuUnsupport(); return 0; } ++static int aufs_is_partially_uptodate(struct page *page, ++ unsigned long from, ++ unsigned long count) ++{ AuUnsupport(); return 0; } ++static void aufs_is_dirty_writeback(struct page *page, bool *dirty, ++ bool *writeback) ++{ AuUnsupport(); } ++static int aufs_error_remove_page(struct address_space *mapping, ++ struct page *page) ++{ AuUnsupport(); return 0; } ++static int aufs_swap_activate(struct swap_info_struct *sis, struct file *file, ++ sector_t *span) ++{ AuUnsupport(); return 0; } ++static void aufs_swap_deactivate(struct file *file) ++{ AuUnsupport(); } ++#endif /* CONFIG_AUFS_DEBUG */ ++ ++const struct address_space_operations aufs_aop = { ++ .readpage = aufs_readpage, ++ .direct_IO = aufs_direct_IO, ++#ifdef CONFIG_AUFS_DEBUG ++ .writepage = aufs_writepage, ++ /* no writepages, because of writepage */ ++ .set_page_dirty = aufs_set_page_dirty, ++ /* no readpages, because of readpage */ ++ .write_begin = aufs_write_begin, ++ .write_end = aufs_write_end, ++ /* no bmap, no block device */ ++ .invalidatepage = aufs_invalidatepage, ++ .releasepage = aufs_releasepage, ++ /* is fallback_migrate_page ok? */ ++ /* .migratepage = aufs_migratepage, */ ++ .isolate_page = aufs_isolate_page, ++ .putback_page = aufs_putback_page, ++ .launder_page = aufs_launder_page, ++ .is_partially_uptodate = aufs_is_partially_uptodate, ++ .is_dirty_writeback = aufs_is_dirty_writeback, ++ .error_remove_page = aufs_error_remove_page, ++ .swap_activate = aufs_swap_activate, ++ .swap_deactivate = aufs_swap_deactivate ++#endif /* CONFIG_AUFS_DEBUG */ ++}; +diff -Naur null/fs/aufs/file.h linux-5.15.36/fs/aufs/file.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/file.h 2022-05-10 16:51:39.871744219 +0300 +@@ -0,0 +1,342 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * file operations ++ */ ++ ++#ifndef __AUFS_FILE_H__ ++#define __AUFS_FILE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++#include "rwsem.h" ++ ++struct au_branch; ++struct au_hfile { ++ struct file *hf_file; ++ struct au_branch *hf_br; ++}; ++ ++struct au_vdir; ++struct au_fidir { ++ aufs_bindex_t fd_bbot; ++ aufs_bindex_t fd_nent; ++ struct au_vdir *fd_vdir_cache; ++ struct au_hfile fd_hfile[]; ++}; ++ ++static inline int au_fidir_sz(int nent) ++{ ++ AuDebugOn(nent < 0); ++ return sizeof(struct au_fidir) + sizeof(struct au_hfile) * nent; ++} ++ ++struct au_finfo { ++ atomic_t fi_generation; ++ ++ struct au_rwsem fi_rwsem; ++ aufs_bindex_t fi_btop; ++ ++ /* do not union them */ ++ struct { /* for non-dir */ ++ struct au_hfile fi_htop; ++ atomic_t fi_mmapped; ++ }; ++ struct au_fidir *fi_hdir; /* for dir only */ ++ ++ struct hlist_bl_node fi_hlist; ++ struct file *fi_file; /* very ugly */ ++ struct rcu_head rcu; ++} ____cacheline_aligned_in_smp; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* file.c */ ++extern const struct address_space_operations aufs_aop; ++unsigned int au_file_roflags(unsigned int flags); ++struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, ++ struct file *file, int force_wr); ++struct au_do_open_args { ++ int aopen; ++ int (*open)(struct file *file, int flags, ++ struct file *h_file); ++ struct au_fidir *fidir; ++ struct file *h_file; ++}; ++int au_do_open(struct file *file, struct au_do_open_args *args); ++int au_reopen_nondir(struct file *file); ++struct au_pin; ++int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin); ++int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file), ++ int wlock, unsigned int fi_lsc); ++int au_do_flush(struct file *file, fl_owner_t id, ++ int (*flush)(struct file *file, fl_owner_t id)); ++ ++/* poll.c */ ++#ifdef CONFIG_AUFS_POLL ++__poll_t aufs_poll(struct file *file, struct poll_table_struct *pt); ++#endif ++ ++#ifdef CONFIG_AUFS_BR_HFSPLUS ++/* hfsplus.c */ ++struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex, ++ int force_wr); ++void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex, ++ struct file *h_file); ++#else ++AuStub(struct file *, au_h_open_pre, return NULL, struct dentry *dentry, ++ aufs_bindex_t bindex, int force_wr) ++AuStubVoid(au_h_open_post, struct dentry *dentry, aufs_bindex_t bindex, ++ struct file *h_file); ++#endif ++ ++/* f_op.c */ ++extern const struct file_operations aufs_file_fop; ++int au_do_open_nondir(struct file *file, int flags, struct file *h_file); ++int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file); ++struct file *au_read_pre(struct file *file, int keep_fi, unsigned int lsc); ++ ++/* finfo.c */ ++void au_hfput(struct au_hfile *hf, int execed); ++void au_set_h_fptr(struct file *file, aufs_bindex_t bindex, ++ struct file *h_file); ++ ++void au_update_figen(struct file *file); ++struct au_fidir *au_fidir_alloc(struct super_block *sb); ++int au_fidir_realloc(struct au_finfo *finfo, int nbr, int may_shrink); ++ ++void au_fi_init_once(void *_fi); ++void au_finfo_fin(struct file *file); ++int au_finfo_init(struct file *file, struct au_fidir *fidir); ++ ++/* ioctl.c */ ++long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg); ++#ifdef CONFIG_COMPAT ++long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd, ++ unsigned long arg); ++long aufs_compat_ioctl_nondir(struct file *file, unsigned int cmd, ++ unsigned long arg); ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_finfo *au_fi(struct file *file) ++{ ++ return file->private_data; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define fi_read_lock(f) au_rw_read_lock(&au_fi(f)->fi_rwsem) ++#define fi_write_lock(f) au_rw_write_lock(&au_fi(f)->fi_rwsem) ++#define fi_read_trylock(f) au_rw_read_trylock(&au_fi(f)->fi_rwsem) ++#define fi_write_trylock(f) au_rw_write_trylock(&au_fi(f)->fi_rwsem) ++/* ++#define fi_read_trylock_nested(f) \ ++ au_rw_read_trylock_nested(&au_fi(f)->fi_rwsem) ++#define fi_write_trylock_nested(f) \ ++ au_rw_write_trylock_nested(&au_fi(f)->fi_rwsem) ++*/ ++ ++#define fi_read_unlock(f) au_rw_read_unlock(&au_fi(f)->fi_rwsem) ++#define fi_write_unlock(f) au_rw_write_unlock(&au_fi(f)->fi_rwsem) ++#define fi_downgrade_lock(f) au_rw_dgrade_lock(&au_fi(f)->fi_rwsem) ++ ++/* lock subclass for finfo */ ++enum { ++ AuLsc_FI_1, ++ AuLsc_FI_2 ++}; ++ ++static inline void fi_read_lock_nested(struct file *f, unsigned int lsc) ++{ ++ au_rw_read_lock_nested(&au_fi(f)->fi_rwsem, lsc); ++} ++ ++static inline void fi_write_lock_nested(struct file *f, unsigned int lsc) ++{ ++ au_rw_write_lock_nested(&au_fi(f)->fi_rwsem, lsc); ++} ++ ++/* ++ * fi_read_lock_1, fi_write_lock_1, ++ * fi_read_lock_2, fi_write_lock_2 ++ */ ++#define AuReadLockFunc(name) \ ++static inline void fi_read_lock_##name(struct file *f) \ ++{ fi_read_lock_nested(f, AuLsc_FI_##name); } ++ ++#define AuWriteLockFunc(name) \ ++static inline void fi_write_lock_##name(struct file *f) \ ++{ fi_write_lock_nested(f, AuLsc_FI_##name); } ++ ++#define AuRWLockFuncs(name) \ ++ AuReadLockFunc(name) \ ++ AuWriteLockFunc(name) ++ ++AuRWLockFuncs(1); ++AuRWLockFuncs(2); ++ ++#undef AuReadLockFunc ++#undef AuWriteLockFunc ++#undef AuRWLockFuncs ++ ++#define FiMustNoWaiters(f) AuRwMustNoWaiters(&au_fi(f)->fi_rwsem) ++#define FiMustAnyLock(f) AuRwMustAnyLock(&au_fi(f)->fi_rwsem) ++#define FiMustWriteLock(f) AuRwMustWriteLock(&au_fi(f)->fi_rwsem) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* todo: hard/soft set? */ ++static inline aufs_bindex_t au_fbtop(struct file *file) ++{ ++ FiMustAnyLock(file); ++ return au_fi(file)->fi_btop; ++} ++ ++static inline aufs_bindex_t au_fbbot_dir(struct file *file) ++{ ++ FiMustAnyLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ return au_fi(file)->fi_hdir->fd_bbot; ++} ++ ++static inline struct au_vdir *au_fvdir_cache(struct file *file) ++{ ++ FiMustAnyLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ return au_fi(file)->fi_hdir->fd_vdir_cache; ++} ++ ++static inline void au_set_fbtop(struct file *file, aufs_bindex_t bindex) ++{ ++ FiMustWriteLock(file); ++ au_fi(file)->fi_btop = bindex; ++} ++ ++static inline void au_set_fbbot_dir(struct file *file, aufs_bindex_t bindex) ++{ ++ FiMustWriteLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ au_fi(file)->fi_hdir->fd_bbot = bindex; ++} ++ ++static inline void au_set_fvdir_cache(struct file *file, ++ struct au_vdir *vdir_cache) ++{ ++ FiMustWriteLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ au_fi(file)->fi_hdir->fd_vdir_cache = vdir_cache; ++} ++ ++static inline struct file *au_hf_top(struct file *file) ++{ ++ FiMustAnyLock(file); ++ AuDebugOn(au_fi(file)->fi_hdir); ++ return au_fi(file)->fi_htop.hf_file; ++} ++ ++static inline struct file *au_hf_dir(struct file *file, aufs_bindex_t bindex) ++{ ++ FiMustAnyLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ return au_fi(file)->fi_hdir->fd_hfile[0 + bindex].hf_file; ++} ++ ++/* todo: memory barrier? */ ++static inline unsigned int au_figen(struct file *f) ++{ ++ return atomic_read(&au_fi(f)->fi_generation); ++} ++ ++static inline void au_set_mmapped(struct file *f) ++{ ++ if (atomic_inc_return(&au_fi(f)->fi_mmapped)) ++ return; ++ pr_warn("fi_mmapped wrapped around\n"); ++ while (!atomic_inc_return(&au_fi(f)->fi_mmapped)) ++ ; ++} ++ ++static inline void au_unset_mmapped(struct file *f) ++{ ++ atomic_dec(&au_fi(f)->fi_mmapped); ++} ++ ++static inline int au_test_mmapped(struct file *f) ++{ ++ return atomic_read(&au_fi(f)->fi_mmapped); ++} ++ ++/* customize vma->vm_file */ ++ ++static inline void au_do_vm_file_reset(struct vm_area_struct *vma, ++ struct file *file) ++{ ++ struct file *f; ++ ++ f = vma->vm_file; ++ get_file(file); ++ vma->vm_file = file; ++ fput(f); ++} ++ ++#ifdef CONFIG_MMU ++#define AuDbgVmRegion(file, vma) do {} while (0) ++ ++static inline void au_vm_file_reset(struct vm_area_struct *vma, ++ struct file *file) ++{ ++ au_do_vm_file_reset(vma, file); ++} ++#else ++#define AuDbgVmRegion(file, vma) \ ++ AuDebugOn((vma)->vm_region && (vma)->vm_region->vm_file != (file)) ++ ++static inline void au_vm_file_reset(struct vm_area_struct *vma, ++ struct file *file) ++{ ++ struct file *f; ++ ++ au_do_vm_file_reset(vma, file); ++ f = vma->vm_region->vm_file; ++ get_file(file); ++ vma->vm_region->vm_file = file; ++ fput(f); ++} ++#endif /* CONFIG_MMU */ ++ ++/* handle vma->vm_prfile */ ++static inline void au_vm_prfile_set(struct vm_area_struct *vma, ++ struct file *file) ++{ ++ get_file(file); ++ vma->vm_prfile = file; ++#ifndef CONFIG_MMU ++ get_file(file); ++ vma->vm_region->vm_prfile = file; ++#endif ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_FILE_H__ */ +diff -Naur null/fs/aufs/finfo.c linux-5.15.36/fs/aufs/finfo.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/finfo.c 2022-05-10 16:51:39.871744219 +0300 +@@ -0,0 +1,149 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * file private data ++ */ ++ ++#include "aufs.h" ++ ++void au_hfput(struct au_hfile *hf, int execed) ++{ ++ if (execed) ++ allow_write_access(hf->hf_file); ++ fput(hf->hf_file); ++ hf->hf_file = NULL; ++ au_lcnt_dec(&hf->hf_br->br_nfiles); ++ hf->hf_br = NULL; ++} ++ ++void au_set_h_fptr(struct file *file, aufs_bindex_t bindex, struct file *val) ++{ ++ struct au_finfo *finfo = au_fi(file); ++ struct au_hfile *hf; ++ struct au_fidir *fidir; ++ ++ fidir = finfo->fi_hdir; ++ if (!fidir) { ++ AuDebugOn(finfo->fi_btop != bindex); ++ hf = &finfo->fi_htop; ++ } else ++ hf = fidir->fd_hfile + bindex; ++ ++ if (hf && hf->hf_file) ++ au_hfput(hf, vfsub_file_execed(file)); ++ if (val) { ++ FiMustWriteLock(file); ++ AuDebugOn(IS_ERR_OR_NULL(file->f_path.dentry)); ++ hf->hf_file = val; ++ hf->hf_br = au_sbr(file->f_path.dentry->d_sb, bindex); ++ } ++} ++ ++void au_update_figen(struct file *file) ++{ ++ atomic_set(&au_fi(file)->fi_generation, au_digen(file->f_path.dentry)); ++ /* smp_mb(); */ /* atomic_set */ ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_fidir *au_fidir_alloc(struct super_block *sb) ++{ ++ struct au_fidir *fidir; ++ int nbr; ++ ++ nbr = au_sbbot(sb) + 1; ++ if (nbr < 2) ++ nbr = 2; /* initial allocate for 2 branches */ ++ fidir = kzalloc(au_fidir_sz(nbr), GFP_NOFS); ++ if (fidir) { ++ fidir->fd_bbot = -1; ++ fidir->fd_nent = nbr; ++ } ++ ++ return fidir; ++} ++ ++int au_fidir_realloc(struct au_finfo *finfo, int nbr, int may_shrink) ++{ ++ int err; ++ struct au_fidir *fidir, *p; ++ ++ AuRwMustWriteLock(&finfo->fi_rwsem); ++ fidir = finfo->fi_hdir; ++ AuDebugOn(!fidir); ++ ++ err = -ENOMEM; ++ p = au_kzrealloc(fidir, au_fidir_sz(fidir->fd_nent), au_fidir_sz(nbr), ++ GFP_NOFS, may_shrink); ++ if (p) { ++ p->fd_nent = nbr; ++ finfo->fi_hdir = p; ++ err = 0; ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_finfo_fin(struct file *file) ++{ ++ struct au_finfo *finfo; ++ ++ au_lcnt_dec(&au_sbi(file->f_path.dentry->d_sb)->si_nfiles); ++ ++ finfo = au_fi(file); ++ AuDebugOn(finfo->fi_hdir); ++ AuRwDestroy(&finfo->fi_rwsem); ++ au_cache_free_finfo(finfo); ++} ++ ++void au_fi_init_once(void *_finfo) ++{ ++ struct au_finfo *finfo = _finfo; ++ ++ au_rw_init(&finfo->fi_rwsem); ++} ++ ++int au_finfo_init(struct file *file, struct au_fidir *fidir) ++{ ++ int err; ++ struct au_finfo *finfo; ++ struct dentry *dentry; ++ ++ err = -ENOMEM; ++ dentry = file->f_path.dentry; ++ finfo = au_cache_alloc_finfo(); ++ if (unlikely(!finfo)) ++ goto out; ++ ++ err = 0; ++ au_lcnt_inc(&au_sbi(dentry->d_sb)->si_nfiles); ++ au_rw_write_lock(&finfo->fi_rwsem); ++ finfo->fi_btop = -1; ++ finfo->fi_hdir = fidir; ++ atomic_set(&finfo->fi_generation, au_digen(dentry)); ++ /* smp_mb(); */ /* atomic_set */ ++ ++ file->private_data = finfo; ++ ++out: ++ return err; ++} +diff -Naur null/fs/aufs/f_op.c linux-5.15.36/fs/aufs/f_op.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/f_op.c 2022-05-10 16:51:39.870744219 +0300 +@@ -0,0 +1,771 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * file and vm operations ++ */ ++ ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++int au_do_open_nondir(struct file *file, int flags, struct file *h_file) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct dentry *dentry, *h_dentry; ++ struct au_finfo *finfo; ++ struct inode *h_inode; ++ ++ FiMustWriteLock(file); ++ ++ err = 0; ++ dentry = file->f_path.dentry; ++ AuDebugOn(IS_ERR_OR_NULL(dentry)); ++ finfo = au_fi(file); ++ memset(&finfo->fi_htop, 0, sizeof(finfo->fi_htop)); ++ atomic_set(&finfo->fi_mmapped, 0); ++ bindex = au_dbtop(dentry); ++ if (!h_file) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ err = vfsub_test_mntns(file->f_path.mnt, h_dentry->d_sb); ++ if (unlikely(err)) ++ goto out; ++ h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0); ++ if (IS_ERR(h_file)) { ++ err = PTR_ERR(h_file); ++ goto out; ++ } ++ } else { ++ h_dentry = h_file->f_path.dentry; ++ err = vfsub_test_mntns(file->f_path.mnt, h_dentry->d_sb); ++ if (unlikely(err)) ++ goto out; ++ /* br ref is already inc-ed */ ++ } ++ ++ if ((flags & __O_TMPFILE) ++ && !(flags & O_EXCL)) { ++ h_inode = file_inode(h_file); ++ spin_lock(&h_inode->i_lock); ++ h_inode->i_state |= I_LINKABLE; ++ spin_unlock(&h_inode->i_lock); ++ } ++ au_set_fbtop(file, bindex); ++ au_set_h_fptr(file, bindex, h_file); ++ au_update_figen(file); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ ++out: ++ return err; ++} ++ ++static int aufs_open_nondir(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ int err; ++ struct super_block *sb; ++ struct au_do_open_args args = { ++ .open = au_do_open_nondir ++ }; ++ ++ AuDbg("%pD, f_flags 0x%x, f_mode 0x%x\n", ++ file, vfsub_file_flags(file), file->f_mode); ++ ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ err = au_do_open(file, &args); ++ si_read_unlock(sb); ++ return err; ++} ++ ++int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file) ++{ ++ struct au_finfo *finfo; ++ aufs_bindex_t bindex; ++ ++ finfo = au_fi(file); ++ au_hbl_del(&finfo->fi_hlist, ++ &au_sbi(file->f_path.dentry->d_sb)->si_files); ++ bindex = finfo->fi_btop; ++ if (bindex >= 0) ++ au_set_h_fptr(file, bindex, NULL); ++ ++ au_finfo_fin(file); ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_flush_nondir(struct file *file, fl_owner_t id) ++{ ++ int err; ++ struct file *h_file; ++ ++ err = 0; ++ h_file = au_hf_top(file); ++ if (h_file) ++ err = vfsub_flush(h_file, id); ++ return err; ++} ++ ++static int aufs_flush_nondir(struct file *file, fl_owner_t id) ++{ ++ return au_do_flush(file, id, au_do_flush_nondir); ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * read and write functions acquire [fdi]_rwsem once, but release before ++ * mmap_sem. This is because to stop a race condition between mmap(2). ++ * Releasing these aufs-rwsem should be safe, no branch-management (by keeping ++ * si_rwsem), no harmful copy-up should happen. Actually copy-up may happen in ++ * read functions after [fdi]_rwsem are released, but it should be harmless. ++ */ ++ ++/* Callers should call au_read_post() or fput() in the end */ ++struct file *au_read_pre(struct file *file, int keep_fi, unsigned int lsc) ++{ ++ struct file *h_file; ++ int err; ++ ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0, lsc); ++ if (!err) { ++ di_read_unlock(file->f_path.dentry, AuLock_IR); ++ h_file = au_hf_top(file); ++ get_file(h_file); ++ if (!keep_fi) ++ fi_read_unlock(file); ++ } else ++ h_file = ERR_PTR(err); ++ ++ return h_file; ++} ++ ++static void au_read_post(struct inode *inode, struct file *h_file) ++{ ++ /* update without lock, I don't think it a problem */ ++ fsstack_copy_attr_atime(inode, file_inode(h_file)); ++ fput(h_file); ++} ++ ++struct au_write_pre { ++ /* input */ ++ unsigned int lsc; ++ ++ /* output */ ++ blkcnt_t blks; ++ aufs_bindex_t btop; ++}; ++ ++/* ++ * return with iinfo is write-locked ++ * callers should call au_write_post() or iinfo_write_unlock() + fput() in the ++ * end ++ */ ++static struct file *au_write_pre(struct file *file, int do_ready, ++ struct au_write_pre *wpre) ++{ ++ struct file *h_file; ++ struct dentry *dentry; ++ int err; ++ unsigned int lsc; ++ struct au_pin pin; ++ ++ lsc = 0; ++ if (wpre) ++ lsc = wpre->lsc; ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1, lsc); ++ h_file = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ dentry = file->f_path.dentry; ++ if (do_ready) { ++ err = au_ready_to_write(file, -1, &pin); ++ if (unlikely(err)) { ++ h_file = ERR_PTR(err); ++ di_write_unlock(dentry); ++ goto out_fi; ++ } ++ } ++ ++ di_downgrade_lock(dentry, /*flags*/0); ++ if (wpre) ++ wpre->btop = au_fbtop(file); ++ h_file = au_hf_top(file); ++ get_file(h_file); ++ if (wpre) ++ wpre->blks = file_inode(h_file)->i_blocks; ++ if (do_ready) ++ au_unpin(&pin); ++ di_read_unlock(dentry, /*flags*/0); ++ ++out_fi: ++ fi_write_unlock(file); ++out: ++ return h_file; ++} ++ ++static void au_write_post(struct inode *inode, struct file *h_file, ++ struct au_write_pre *wpre, ssize_t written) ++{ ++ struct inode *h_inode; ++ ++ au_cpup_attr_timesizes(inode); ++ AuDebugOn(au_ibtop(inode) != wpre->btop); ++ h_inode = file_inode(h_file); ++ inode->i_mode = h_inode->i_mode; ++ ii_write_unlock(inode); ++ /* AuDbg("blks %llu, %llu\n", (u64)blks, (u64)h_inode->i_blocks); */ ++ if (written > 0) ++ au_fhsm_wrote(inode->i_sb, wpre->btop, ++ /*force*/h_inode->i_blocks > wpre->blks); ++ fput(h_file); ++} ++ ++/* ++ * todo: very ugly ++ * it locks both of i_mutex and si_rwsem for read in safe. ++ * if the plink maintenance mode continues forever (that is the problem), ++ * may loop forever. ++ */ ++static void au_mtx_and_read_lock(struct inode *inode) ++{ ++ int err; ++ struct super_block *sb = inode->i_sb; ++ ++ while (1) { ++ inode_lock(inode); ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (!err) ++ break; ++ inode_unlock(inode); ++ si_read_lock(sb, AuLock_NOPLMW); ++ si_read_unlock(sb); ++ } ++} ++ ++static ssize_t au_do_iter(struct file *h_file, int rw, struct kiocb *kio, ++ struct iov_iter *iov_iter) ++{ ++ ssize_t err; ++ struct file *file; ++ ssize_t (*iter)(struct kiocb *, struct iov_iter *); ++ ++ err = security_file_permission(h_file, rw); ++ if (unlikely(err)) ++ goto out; ++ ++ err = -ENOSYS; /* the branch doesn't have its ->(read|write)_iter() */ ++ iter = NULL; ++ if (rw == MAY_READ) ++ iter = h_file->f_op->read_iter; ++ else if (rw == MAY_WRITE) ++ iter = h_file->f_op->write_iter; ++ ++ file = kio->ki_filp; ++ kio->ki_filp = h_file; ++ if (iter) { ++ lockdep_off(); ++ err = iter(kio, iov_iter); ++ lockdep_on(); ++ } else ++ /* currently there is no such fs */ ++ WARN_ON_ONCE(1); ++ kio->ki_filp = file; ++ ++out: ++ return err; ++} ++ ++static ssize_t aufs_read_iter(struct kiocb *kio, struct iov_iter *iov_iter) ++{ ++ ssize_t err; ++ struct file *file, *h_file; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ file = kio->ki_filp; ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/1, /*lsc*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ if (au_test_loopback_kthread()) { ++ au_warn_loopback(h_file->f_path.dentry->d_sb); ++ if (file->f_mapping != h_file->f_mapping) { ++ file->f_mapping = h_file->f_mapping; ++ smp_mb(); /* unnecessary? */ ++ } ++ } ++ fi_read_unlock(file); ++ ++ err = au_do_iter(h_file, MAY_READ, kio, iov_iter); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ au_read_post(inode, h_file); ++ ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++static ssize_t aufs_write_iter(struct kiocb *kio, struct iov_iter *iov_iter) ++{ ++ ssize_t err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *file, *h_file; ++ ++ file = kio->ki_filp; ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ wpre.lsc = 0; ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = au_do_iter(h_file, MAY_WRITE, kio, iov_iter); ++ au_write_post(inode, h_file, &wpre, err); ++ ++out: ++ si_read_unlock(inode->i_sb); ++ inode_unlock(inode); ++ return err; ++} ++ ++/* ++ * We may be able to remove aufs_splice_{read,write}() since almost all FSes ++ * don't have their own .splice_{read,write} implimentations, and they use ++ * generic_file_splice_read() and iter_file_splice_write() who can act like the ++ * simple converters to f_op->iter_read() and ->iter_write(). ++ * But we keep our own implementations because some non-mainlined FSes may have ++ * their own .splice_{read,write} implimentations and aufs doesn't want to take ++ * away an opportunity to co-work with aufs from them. ++ */ ++static ssize_t aufs_splice_read(struct file *file, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags) ++{ ++ ssize_t err; ++ struct file *h_file; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/0, /*lsc*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = vfsub_splice_to(h_file, ppos, pipe, len, flags); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ au_read_post(inode, h_file); ++ ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++static ssize_t ++aufs_splice_write(struct pipe_inode_info *pipe, struct file *file, loff_t *ppos, ++ size_t len, unsigned int flags) ++{ ++ ssize_t err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *h_file; ++ ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ wpre.lsc = 0; ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = vfsub_splice_from(pipe, h_file, ppos, len, flags); ++ au_write_post(inode, h_file, &wpre, err); ++ ++out: ++ si_read_unlock(inode->i_sb); ++ inode_unlock(inode); ++ return err; ++} ++ ++static long aufs_fallocate(struct file *file, int mode, loff_t offset, ++ loff_t len) ++{ ++ long err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *h_file; ++ ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ wpre.lsc = 0; ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ lockdep_off(); ++ err = vfs_fallocate(h_file, mode, offset, len); ++ lockdep_on(); ++ au_write_post(inode, h_file, &wpre, /*written*/1); ++ ++out: ++ si_read_unlock(inode->i_sb); ++ inode_unlock(inode); ++ return err; ++} ++ ++static ssize_t aufs_copy_file_range(struct file *src, loff_t src_pos, ++ struct file *dst, loff_t dst_pos, ++ size_t len, unsigned int flags) ++{ ++ ssize_t err; ++ struct au_write_pre wpre; ++ enum { SRC, DST }; ++ struct { ++ struct inode *inode; ++ struct file *h_file; ++ struct super_block *h_sb; ++ } a[2]; ++#define a_src a[SRC] ++#define a_dst a[DST] ++ ++ err = -EINVAL; ++ a_src.inode = file_inode(src); ++ if (unlikely(!S_ISREG(a_src.inode->i_mode))) ++ goto out; ++ a_dst.inode = file_inode(dst); ++ if (unlikely(!S_ISREG(a_dst.inode->i_mode))) ++ goto out; ++ ++ au_mtx_and_read_lock(a_dst.inode); ++ /* ++ * in order to match the order in di_write_lock2_{child,parent}(), ++ * use f_path.dentry for this comparison. ++ */ ++ if (src->f_path.dentry < dst->f_path.dentry) { ++ a_src.h_file = au_read_pre(src, /*keep_fi*/1, AuLsc_FI_1); ++ err = PTR_ERR(a_src.h_file); ++ if (IS_ERR(a_src.h_file)) ++ goto out_si; ++ ++ wpre.lsc = AuLsc_FI_2; ++ a_dst.h_file = au_write_pre(dst, /*do_ready*/1, &wpre); ++ err = PTR_ERR(a_dst.h_file); ++ if (IS_ERR(a_dst.h_file)) { ++ au_read_post(a_src.inode, a_src.h_file); ++ goto out_si; ++ } ++ } else { ++ wpre.lsc = AuLsc_FI_1; ++ a_dst.h_file = au_write_pre(dst, /*do_ready*/1, &wpre); ++ err = PTR_ERR(a_dst.h_file); ++ if (IS_ERR(a_dst.h_file)) ++ goto out_si; ++ ++ a_src.h_file = au_read_pre(src, /*keep_fi*/1, AuLsc_FI_2); ++ err = PTR_ERR(a_src.h_file); ++ if (IS_ERR(a_src.h_file)) { ++ au_write_post(a_dst.inode, a_dst.h_file, &wpre, ++ /*written*/0); ++ goto out_si; ++ } ++ } ++ ++ err = -EXDEV; ++ a_src.h_sb = file_inode(a_src.h_file)->i_sb; ++ a_dst.h_sb = file_inode(a_dst.h_file)->i_sb; ++ if (unlikely(a_src.h_sb != a_dst.h_sb)) { ++ AuDbgFile(src); ++ AuDbgFile(dst); ++ goto out_file; ++ } ++ ++ err = vfsub_copy_file_range(a_src.h_file, src_pos, a_dst.h_file, ++ dst_pos, len, flags); ++ ++out_file: ++ au_write_post(a_dst.inode, a_dst.h_file, &wpre, err); ++ fi_read_unlock(src); ++ au_read_post(a_src.inode, a_src.h_file); ++out_si: ++ si_read_unlock(a_dst.inode->i_sb); ++ inode_unlock(a_dst.inode); ++out: ++ return err; ++#undef a_src ++#undef a_dst ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * The locking order around current->mmap_sem. ++ * - in most and regular cases ++ * file I/O syscall -- aufs_read() or something ++ * -- si_rwsem for read -- mmap_sem ++ * (Note that [fdi]i_rwsem are released before mmap_sem). ++ * - in mmap case ++ * mmap(2) -- mmap_sem -- aufs_mmap() -- si_rwsem for read -- [fdi]i_rwsem ++ * This AB-BA order is definitely bad, but is not a problem since "si_rwsem for ++ * read" allows multiple processes to acquire it and [fdi]i_rwsem are not held ++ * in file I/O. Aufs needs to stop lockdep in aufs_mmap() though. ++ * It means that when aufs acquires si_rwsem for write, the process should never ++ * acquire mmap_sem. ++ * ++ * Actually aufs_iterate() holds [fdi]i_rwsem before mmap_sem, but this is not a ++ * problem either since any directory is not able to be mmap-ed. ++ * The similar scenario is applied to aufs_readlink() too. ++ */ ++ ++#if 0 /* stop calling security_file_mmap() */ ++/* cf. linux/include/linux/mman.h: calc_vm_prot_bits() */ ++#define AuConv_VM_PROT(f, b) _calc_vm_trans(f, VM_##b, PROT_##b) ++ ++static unsigned long au_arch_prot_conv(unsigned long flags) ++{ ++ /* currently ppc64 only */ ++#ifdef CONFIG_PPC64 ++ /* cf. linux/arch/powerpc/include/asm/mman.h */ ++ AuDebugOn(arch_calc_vm_prot_bits(-1) != VM_SAO); ++ return AuConv_VM_PROT(flags, SAO); ++#else ++ AuDebugOn(arch_calc_vm_prot_bits(-1)); ++ return 0; ++#endif ++} ++ ++static unsigned long au_prot_conv(unsigned long flags) ++{ ++ return AuConv_VM_PROT(flags, READ) ++ | AuConv_VM_PROT(flags, WRITE) ++ | AuConv_VM_PROT(flags, EXEC) ++ | au_arch_prot_conv(flags); ++} ++ ++/* cf. linux/include/linux/mman.h: calc_vm_flag_bits() */ ++#define AuConv_VM_MAP(f, b) _calc_vm_trans(f, VM_##b, MAP_##b) ++ ++static unsigned long au_flag_conv(unsigned long flags) ++{ ++ return AuConv_VM_MAP(flags, GROWSDOWN) ++ | AuConv_VM_MAP(flags, DENYWRITE) ++ | AuConv_VM_MAP(flags, LOCKED); ++} ++#endif ++ ++static int aufs_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ int err; ++ const unsigned char wlock ++ = (file->f_mode & FMODE_WRITE) && (vma->vm_flags & VM_SHARED); ++ struct super_block *sb; ++ struct file *h_file; ++ struct inode *inode; ++ ++ AuDbgVmRegion(file, vma); ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ lockdep_off(); ++ si_read_lock(sb, AuLock_NOPLMW); ++ ++ h_file = au_write_pre(file, wlock, /*wpre*/NULL); ++ lockdep_on(); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = 0; ++ au_set_mmapped(file); ++ au_vm_file_reset(vma, h_file); ++ /* ++ * we cannot call security_mmap_file() here since it may acquire ++ * mmap_sem or i_mutex. ++ * ++ * err = security_mmap_file(h_file, au_prot_conv(vma->vm_flags), ++ * au_flag_conv(vma->vm_flags)); ++ */ ++ if (!err) ++ err = call_mmap(h_file, vma); ++ if (!err) { ++ au_vm_prfile_set(vma, file); ++ fsstack_copy_attr_atime(inode, file_inode(h_file)); ++ goto out_fput; /* success */ ++ } ++ au_unset_mmapped(file); ++ au_vm_file_reset(vma, file); ++ ++out_fput: ++ lockdep_off(); ++ ii_write_unlock(inode); ++ lockdep_on(); ++ fput(h_file); ++out: ++ lockdep_off(); ++ si_read_unlock(sb); ++ lockdep_on(); ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_fsync_nondir(struct file *file, loff_t start, loff_t end, ++ int datasync) ++{ ++ int err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *h_file; ++ ++ err = 0; /* -EBADF; */ /* posix? */ ++ if (unlikely(!(file->f_mode & FMODE_WRITE))) ++ goto out; ++ ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ wpre.lsc = 0; ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out_unlock; ++ ++ err = vfsub_fsync(h_file, &h_file->f_path, datasync); ++ au_write_post(inode, h_file, &wpre, /*written*/0); ++ ++out_unlock: ++ si_read_unlock(inode->i_sb); ++ inode_unlock(inode); ++out: ++ return err; ++} ++ ++static int aufs_fasync(int fd, struct file *file, int flag) ++{ ++ int err; ++ struct file *h_file; ++ struct super_block *sb; ++ ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/0, /*lsc*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ if (h_file->f_op->fasync) ++ err = h_file->f_op->fasync(fd, h_file, flag); ++ fput(h_file); /* instead of au_read_post() */ ++ ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++static int aufs_setfl(struct file *file, unsigned long arg) ++{ ++ int err; ++ struct file *h_file; ++ struct super_block *sb; ++ ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/0, /*lsc*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ /* stop calling h_file->fasync */ ++ arg |= vfsub_file_flags(file) & FASYNC; ++ err = setfl(/*unused fd*/-1, h_file, arg); ++ fput(h_file); /* instead of au_read_post() */ ++ ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* no one supports this operation, currently */ ++#if 0 /* reserved for future use */ ++static ssize_t aufs_sendpage(struct file *file, struct page *page, int offset, ++ size_t len, loff_t *pos, int more) ++{ ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++const struct file_operations aufs_file_fop = { ++ .owner = THIS_MODULE, ++ ++ .llseek = default_llseek, ++ ++ .read_iter = aufs_read_iter, ++ .write_iter = aufs_write_iter, ++ ++#ifdef CONFIG_AUFS_POLL ++ .poll = aufs_poll, ++#endif ++ .unlocked_ioctl = aufs_ioctl_nondir, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = aufs_compat_ioctl_nondir, ++#endif ++ .mmap = aufs_mmap, ++ .open = aufs_open_nondir, ++ .flush = aufs_flush_nondir, ++ .release = aufs_release_nondir, ++ .fsync = aufs_fsync_nondir, ++ .fasync = aufs_fasync, ++ /* .sendpage = aufs_sendpage, */ ++ .setfl = aufs_setfl, ++ .splice_write = aufs_splice_write, ++ .splice_read = aufs_splice_read, ++#if 0 /* reserved for future use */ ++ .aio_splice_write = aufs_aio_splice_write, ++ .aio_splice_read = aufs_aio_splice_read, ++#endif ++ .fallocate = aufs_fallocate, ++ .copy_file_range = aufs_copy_file_range ++}; +diff -Naur null/fs/aufs/fsctx.c linux-5.15.36/fs/aufs/fsctx.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/fsctx.c 2022-05-10 16:51:39.871744219 +0300 +@@ -0,0 +1,1242 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2022 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * fs context, aka new mount api ++ */ ++ ++#include ++#include "aufs.h" ++ ++struct au_fsctx_opts { ++ aufs_bindex_t bindex; ++ unsigned char skipped; ++ struct au_opt *opt, *opt_tail; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ struct au_opts opts; ++}; ++ ++/* stop extra interpretation of errno in mount(8), and strange error messages */ ++static int cvt_err(int err) ++{ ++ AuTraceErr(err); ++ ++ switch (err) { ++ case -ENOENT: ++ case -ENOTDIR: ++ case -EEXIST: ++ case -EIO: ++ err = -EINVAL; ++ } ++ return err; ++} ++ ++static int au_fsctx_reconfigure(struct fs_context *fc) ++{ ++ int err, do_dx; ++ unsigned int mntflags; ++ struct dentry *root; ++ struct super_block *sb; ++ struct inode *inode; ++ struct au_fsctx_opts *a = fc->fs_private; ++ ++ AuDbg("fc %p\n", fc); ++ ++ root = fc->root; ++ sb = root->d_sb; ++ err = si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (!err) { ++ di_write_lock_child(root); ++ err = au_opts_verify(sb, fc->sb_flags, /*pending*/0); ++ aufs_write_unlock(root); ++ } ++ ++ inode = d_inode(root); ++ inode_lock(inode); ++ err = si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out; ++ di_write_lock_child(root); ++ ++ /* au_opts_remount() may return an error */ ++ err = au_opts_remount(sb, &a->opts); ++ ++ if (au_ftest_opts(a->opts.flags, REFRESH)) ++ au_remount_refresh(sb, au_ftest_opts(a->opts.flags, ++ REFRESH_IDOP)); ++ ++ if (au_ftest_opts(a->opts.flags, REFRESH_DYAOP)) { ++ mntflags = au_mntflags(sb); ++ do_dx = !!au_opt_test(mntflags, DIO); ++ au_dy_arefresh(do_dx); ++ } ++ ++ au_fhsm_wrote_all(sb, /*force*/1); /* ?? */ ++ aufs_write_unlock(root); ++ ++out: ++ inode_unlock(inode); ++ err = cvt_err(err); ++ AuTraceErr(err); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_fsctx_fill_super(struct super_block *sb, struct fs_context *fc) ++{ ++ int err; ++ struct au_fsctx_opts *a = fc->fs_private; ++ struct au_sbinfo *sbinfo = a->sbinfo; ++ struct dentry *root; ++ struct inode *inode; ++ ++ sbinfo->si_sb = sb; ++ sb->s_fs_info = sbinfo; ++ kobject_get(&sbinfo->si_kobj); ++ ++ __si_write_lock(sb); ++ si_pid_set(sb); ++ au_sbilist_add(sb); ++ ++ /* all timestamps always follow the ones on the branch */ ++ sb->s_flags |= SB_NOATIME | SB_NODIRATIME; ++ sb->s_flags |= SB_I_VERSION; /* do we really need this? */ ++ sb->s_op = &aufs_sop; ++ sb->s_d_op = &aufs_dop; ++ sb->s_magic = AUFS_SUPER_MAGIC; ++ sb->s_maxbytes = 0; ++ sb->s_stack_depth = 1; ++ au_export_init(sb); ++ au_xattr_init(sb); ++ ++ err = au_alloc_root(sb); ++ if (unlikely(err)) { ++ si_write_unlock(sb); ++ goto out; ++ } ++ root = sb->s_root; ++ inode = d_inode(root); ++ ii_write_lock_parent(inode); ++ aufs_write_unlock(root); ++ ++ /* lock vfs_inode first, then aufs. */ ++ inode_lock(inode); ++ aufs_write_lock(root); ++ err = au_opts_mount(sb, &a->opts); ++ AuTraceErr(err); ++ if (!err && au_ftest_si(sbinfo, NO_DREVAL)) { ++ sb->s_d_op = &aufs_dop_noreval; ++ /* infofc(fc, "%ps", sb->s_d_op); */ ++ pr_info("%ps\n", sb->s_d_op); ++ au_refresh_dop(root, /*force_reval*/0); ++ sbinfo->si_iop_array = aufs_iop_nogetattr; ++ au_refresh_iop(inode, /*force_getattr*/0); ++ } ++ aufs_write_unlock(root); ++ inode_unlock(inode); ++ if (!err) ++ goto out; /* success */ ++ ++ dput(root); ++ sb->s_root = NULL; ++ ++out: ++ if (unlikely(err)) ++ kobject_put(&sbinfo->si_kobj); ++ AuTraceErr(err); ++ err = cvt_err(err); ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_fsctx_get_tree(struct fs_context *fc) ++{ ++ int err; ++ ++ AuDbg("fc %p\n", fc); ++ err = get_tree_nodev(fc, au_fsctx_fill_super); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_fsctx_dump(struct au_opts *opts) ++{ ++#ifdef CONFIG_AUFS_DEBUG ++ /* reduce stack space */ ++ union { ++ struct au_opt_add *add; ++ struct au_opt_del *del; ++ struct au_opt_mod *mod; ++ struct au_opt_xino *xino; ++ struct au_opt_xino_itrunc *xino_itrunc; ++ struct au_opt_wbr_create *create; ++ } u; ++ struct au_opt *opt; ++ ++ opt = opts->opt; ++ while (opt->type != Opt_tail) { ++ switch (opt->type) { ++ case Opt_add: ++ u.add = &opt->add; ++ AuDbg("add {b%d, %s, 0x%x, %p}\n", ++ u.add->bindex, u.add->pathname, u.add->perm, ++ u.add->path.dentry); ++ break; ++ case Opt_del: ++ fallthrough; ++ case Opt_idel: ++ u.del = &opt->del; ++ AuDbg("del {%s, %p}\n", ++ u.del->pathname, u.del->h_path.dentry); ++ break; ++ case Opt_mod: ++ fallthrough; ++ case Opt_imod: ++ u.mod = &opt->mod; ++ AuDbg("mod {%s, 0x%x, %p}\n", ++ u.mod->path, u.mod->perm, u.mod->h_root); ++ break; ++ case Opt_append: ++ u.add = &opt->add; ++ AuDbg("append {b%d, %s, 0x%x, %p}\n", ++ u.add->bindex, u.add->pathname, u.add->perm, ++ u.add->path.dentry); ++ break; ++ case Opt_prepend: ++ u.add = &opt->add; ++ AuDbg("prepend {b%d, %s, 0x%x, %p}\n", ++ u.add->bindex, u.add->pathname, u.add->perm, ++ u.add->path.dentry); ++ break; ++ ++ case Opt_dirwh: ++ AuDbg("dirwh %d\n", opt->dirwh); ++ break; ++ case Opt_rdcache: ++ AuDbg("rdcache %d\n", opt->rdcache); ++ break; ++ case Opt_rdblk: ++ AuDbg("rdblk %d\n", opt->rdblk); ++ break; ++ case Opt_rdhash: ++ AuDbg("rdhash %u\n", opt->rdhash); ++ break; ++ ++ case Opt_xino: ++ u.xino = &opt->xino; ++ AuDbg("xino {%s %pD}\n", u.xino->path, u.xino->file); ++ break; ++ ++#define au_fsctx_TF(name) \ ++ case Opt_##name: \ ++ if (opt->tf) \ ++ AuLabel(name); \ ++ else \ ++ AuLabel(no##name); \ ++ break; ++ ++ /* simple true/false flag */ ++ au_fsctx_TF(trunc_xino); ++ au_fsctx_TF(trunc_xib); ++ au_fsctx_TF(dirperm1); ++ au_fsctx_TF(plink); ++ au_fsctx_TF(shwh); ++ au_fsctx_TF(dio); ++ au_fsctx_TF(warn_perm); ++ au_fsctx_TF(verbose); ++ au_fsctx_TF(sum); ++ au_fsctx_TF(dirren); ++ au_fsctx_TF(acl); ++#undef au_fsctx_TF ++ ++ case Opt_trunc_xino_path: ++ fallthrough; ++ case Opt_itrunc_xino: ++ u.xino_itrunc = &opt->xino_itrunc; ++ AuDbg("trunc_xino %d\n", u.xino_itrunc->bindex); ++ break; ++ case Opt_noxino: ++ AuLabel(noxino); ++ break; ++ ++ case Opt_list_plink: ++ AuLabel(list_plink); ++ break; ++ case Opt_udba: ++ AuDbg("udba %d, %s\n", ++ opt->udba, au_optstr_udba(opt->udba)); ++ break; ++ case Opt_diropq_a: ++ AuLabel(diropq_a); ++ break; ++ case Opt_diropq_w: ++ AuLabel(diropq_w); ++ break; ++ case Opt_wsum: ++ AuLabel(wsum); ++ break; ++ case Opt_wbr_create: ++ u.create = &opt->wbr_create; ++ AuDbg("create %d, %s\n", u.create->wbr_create, ++ au_optstr_wbr_create(u.create->wbr_create)); ++ switch (u.create->wbr_create) { ++ case AuWbrCreate_MFSV: ++ fallthrough; ++ case AuWbrCreate_PMFSV: ++ AuDbg("%d sec\n", u.create->mfs_second); ++ break; ++ case AuWbrCreate_MFSRR: ++ fallthrough; ++ case AuWbrCreate_TDMFS: ++ AuDbg("%llu watermark\n", ++ u.create->mfsrr_watermark); ++ break; ++ case AuWbrCreate_MFSRRV: ++ fallthrough; ++ case AuWbrCreate_TDMFSV: ++ fallthrough; ++ case AuWbrCreate_PMFSRRV: ++ AuDbg("%llu watermark, %d sec\n", ++ u.create->mfsrr_watermark, ++ u.create->mfs_second); ++ break; ++ } ++ break; ++ case Opt_wbr_copyup: ++ AuDbg("copyup %d, %s\n", opt->wbr_copyup, ++ au_optstr_wbr_copyup(opt->wbr_copyup)); ++ break; ++ case Opt_fhsm_sec: ++ AuDbg("fhsm_sec %u\n", opt->fhsm_second); ++ break; ++ ++ default: ++ AuDbg("type %d\n", opt->type); ++ BUG(); ++ } ++ opt++; ++ } ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * For conditionally compiled mount options. ++ * Instead of fsparam_flag_no(), use this macro to distinguish ignore_silent. ++ */ ++#define au_ignore_flag(name, action) \ ++ fsparam_flag(name, action), \ ++ fsparam_flag("no" name, Opt_ignore_silent) ++ ++const struct fs_parameter_spec aufs_fsctx_paramspec[] = { ++ fsparam_string("br", Opt_br), ++ ++ /* "add=%d:%s" or "ins=%d:%s" */ ++ fsparam_string("add", Opt_add), ++ fsparam_string("ins", Opt_add), ++ fsparam_path("append", Opt_append), ++ fsparam_path("prepend", Opt_prepend), ++ ++ fsparam_path("del", Opt_del), ++ /* fsparam_s32("idel", Opt_idel), */ ++ fsparam_path("mod", Opt_mod), ++ /* fsparam_string("imod", Opt_imod), */ ++ ++ fsparam_s32("dirwh", Opt_dirwh), ++ ++ fsparam_path("xino", Opt_xino), ++ fsparam_flag("noxino", Opt_noxino), ++ fsparam_flag_no("trunc_xino", Opt_trunc_xino), ++ /* "trunc_xino_v=%d:%d" */ ++ /* fsparam_string("trunc_xino_v", Opt_trunc_xino_v), */ ++ fsparam_path("trunc_xino", Opt_trunc_xino_path), ++ fsparam_s32("itrunc_xino", Opt_itrunc_xino), ++ /* fsparam_path("zxino", Opt_zxino), */ ++ fsparam_flag_no("trunc_xib", Opt_trunc_xib), ++ ++#ifdef CONFIG_PROC_FS ++ fsparam_flag_no("plink", Opt_plink), ++#else ++ au_ignore_flag("plink", Opt_ignore), ++#endif ++ ++#ifdef CONFIG_AUFS_DEBUG ++ fsparam_flag("list_plink", Opt_list_plink), ++#endif ++ ++ fsparam_string("udba", Opt_udba), ++ ++ fsparam_flag_no("dio", Opt_dio), ++ ++#ifdef CONFIG_AUFS_DIRREN ++ fsparam_flag_no("dirren", Opt_dirren), ++#else ++ au_ignore_flag("dirren", Opt_ignore), ++#endif ++ ++#ifdef CONFIG_AUFS_FHSM ++ fsparam_s32("fhsm_sec", Opt_fhsm_sec), ++#else ++ fsparam_s32("fhsm_sec", Opt_ignore), ++#endif ++ ++ /* always | a | whiteouted | w */ ++ fsparam_string("diropq", Opt_diropq), ++ ++ fsparam_flag_no("warn_perm", Opt_warn_perm), ++ ++#ifdef CONFIG_AUFS_SHWH ++ fsparam_flag_no("shwh", Opt_shwh), ++#else ++ au_ignore_flag("shwh", Opt_err), ++#endif ++ ++ fsparam_flag_no("dirperm1", Opt_dirperm1), ++ ++ fsparam_flag_no("verbose", Opt_verbose), ++ fsparam_flag("v", Opt_verbose), ++ fsparam_flag("quiet", Opt_noverbose), ++ fsparam_flag("q", Opt_noverbose), ++ /* user-space may handle this */ ++ fsparam_flag("silent", Opt_noverbose), ++ ++ fsparam_flag_no("sum", Opt_sum), ++ fsparam_flag("wsum", Opt_wsum), ++ ++ fsparam_s32("rdcache", Opt_rdcache), ++ /* "def" or s32 */ ++ fsparam_string("rdblk", Opt_rdblk), ++ /* "def" or s32 */ ++ fsparam_string("rdhash", Opt_rdhash), ++ ++ fsparam_string("create", Opt_wbr_create), ++ fsparam_string("create_policy", Opt_wbr_create), ++ fsparam_string("cpup", Opt_wbr_copyup), ++ fsparam_string("copyup", Opt_wbr_copyup), ++ fsparam_string("copyup_policy", Opt_wbr_copyup), ++ ++ /* generic VFS flag */ ++#ifdef CONFIG_FS_POSIX_ACL ++ fsparam_flag_no("acl", Opt_acl), ++#else ++ au_ignore_flag("acl"), ++#endif ++ ++ /* internal use for the scripts */ ++ fsparam_string("si", Opt_ignore_silent), ++ ++ /* obsoleted, keep them temporary */ ++ fsparam_flag("nodlgt", Opt_ignore_silent), ++ fsparam_flag("clean_plink", Opt_ignore), ++ fsparam_string("dirs", Opt_br), ++ fsparam_u32("debug", Opt_ignore), ++ /* "whiteout" or "all" */ ++ fsparam_string("delete", Opt_ignore), ++ fsparam_string("imap", Opt_ignore), ++ ++ /* temporary workaround, due to old mount(8)? */ ++ fsparam_flag("relatime", Opt_ignore_silent), ++ ++ {} ++}; ++ ++static int au_fsctx_parse_do_add(struct fs_context *fc, struct au_opt *opt, ++ char *brspec, size_t speclen, ++ aufs_bindex_t bindex) ++{ ++ int err; ++ char *p; ++ ++ AuDbg("brspec %s\n", brspec); ++ ++ err = -ENOMEM; ++ if (!speclen) ++ speclen = strlen(brspec); ++ /* will be freed by au_fsctx_free() */ ++ p = kmemdup_nul(brspec, speclen, GFP_NOFS); ++ if (unlikely(!p)) { ++ errorfc(fc, "failed in %s", brspec); ++ goto out; ++ } ++ err = au_opt_add(opt, p, fc->sb_flags, bindex); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_fsctx_parse_br(struct fs_context *fc, char *brspec) ++{ ++ int err; ++ char *p; ++ struct au_fsctx_opts *a = fc->fs_private; ++ struct au_opt *opt = a->opt; ++ aufs_bindex_t bindex = a->bindex; ++ ++ AuDbg("brspec %s\n", brspec); ++ ++ err = -EINVAL; ++ while ((p = strsep(&brspec, ":")) && *p) { ++ err = au_fsctx_parse_do_add(fc, opt, p, /*len*/0, bindex); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ break; ++ bindex++; ++ opt++; ++ if (unlikely(opt > a->opt_tail)) { ++ err = -E2BIG; ++ bindex--; ++ opt--; ++ break; ++ } ++ opt->type = Opt_tail; ++ a->skipped = 1; ++ } ++ a->bindex = bindex; ++ a->opt = opt; ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_fsctx_parse_add(struct fs_context *fc, char *addspec) ++{ ++ int err, n; ++ char *p; ++ struct au_fsctx_opts *a = fc->fs_private; ++ struct au_opt *opt = a->opt; ++ ++ err = -EINVAL; ++ p = strchr(addspec, ':'); ++ if (unlikely(!p)) { ++ errorfc(fc, "bad arg in %s", addspec); ++ goto out; ++ } ++ *p++ = '\0'; ++ err = kstrtoint(addspec, 0, &n); ++ if (unlikely(err)) { ++ errorfc(fc, "bad integer in %s", addspec); ++ goto out; ++ } ++ AuDbg("n %d\n", n); ++ err = au_fsctx_parse_do_add(fc, opt, p, /*len*/0, n); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_fsctx_parse_del(struct fs_context *fc, struct au_opt_del *del, ++ struct fs_parameter *param) ++{ ++ int err; ++ ++ err = -ENOMEM; ++ /* will be freed by au_fsctx_free() */ ++ del->pathname = kmemdup_nul(param->string, param->size, GFP_NOFS); ++ if (unlikely(!del->pathname)) ++ goto out; ++ AuDbg("del %s\n", del->pathname); ++ err = vfsub_kern_path(del->pathname, AuOpt_LkupDirFlags, &del->h_path); ++ if (unlikely(err)) ++ errorfc(fc, "lookup failed %s (%d)", del->pathname, err); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++#if 0 /* reserved for future use */ ++static int au_fsctx_parse_idel(struct fs_context *fc, struct au_opt_del *del, ++ aufs_bindex_t bindex) ++{ ++ int err; ++ struct super_block *sb; ++ struct dentry *root; ++ struct au_fsctx_opts *a = fc->fs_private; ++ ++ sb = a->sb; ++ AuDebugOn(!sb); ++ ++ err = -EINVAL; ++ root = sb->s_root; ++ aufs_read_lock(root, AuLock_FLUSH); ++ if (bindex < 0 || au_sbbot(sb) < bindex) { ++ errorfc(fc, "out of bounds, %d", bindex); ++ goto out; ++ } ++ ++ err = 0; ++ del->h_path.dentry = dget(au_h_dptr(root, bindex)); ++ del->h_path.mnt = mntget(au_sbr_mnt(sb, bindex)); ++ ++out: ++ aufs_read_unlock(root, !AuLock_IR); ++ AuTraceErr(err); ++ return err; ++} ++#endif ++ ++static int au_fsctx_parse_mod(struct fs_context *fc, struct au_opt_mod *mod, ++ struct fs_parameter *param) ++{ ++ int err; ++ struct path path; ++ char *p; ++ ++ err = -ENOMEM; ++ /* will be freed by au_fsctx_free() */ ++ mod->path = kmemdup_nul(param->string, param->size, GFP_NOFS); ++ if (unlikely(!mod->path)) ++ goto out; ++ ++ err = -EINVAL; ++ p = strchr(mod->path, '='); ++ if (unlikely(!p)) { ++ errorfc(fc, "no permission %s", mod->path); ++ goto out; ++ } ++ ++ *p++ = 0; ++ err = vfsub_kern_path(mod->path, AuOpt_LkupDirFlags, &path); ++ if (unlikely(err)) { ++ errorfc(fc, "lookup failed %s (%d)", mod->path, err); ++ goto out; ++ } ++ ++ mod->perm = au_br_perm_val(p); ++ AuDbg("mod path %s, perm 0x%x, %s", mod->path, mod->perm, p); ++ mod->h_root = dget(path.dentry); ++ path_put(&path); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++#if 0 /* reserved for future use */ ++static int au_fsctx_parse_imod(struct fs_context *fc, struct au_opt_mod *mod, ++ char *ibrspec) ++{ ++ int err, n; ++ char *p; ++ struct super_block *sb; ++ struct dentry *root; ++ struct au_fsctx_opts *a = fc->fs_private; ++ ++ sb = a->sb; ++ AuDebugOn(!sb); ++ ++ err = -EINVAL; ++ p = strchr(ibrspec, ':'); ++ if (unlikely(!p)) { ++ errorfc(fc, "no index, %s", ibrspec); ++ goto out; ++ } ++ *p++ = '\0'; ++ err = kstrtoint(ibrspec, 0, &n); ++ if (unlikely(err)) { ++ errorfc(fc, "bad integer in %s", ibrspec); ++ goto out; ++ } ++ AuDbg("n %d\n", n); ++ ++ root = sb->s_root; ++ aufs_read_lock(root, AuLock_FLUSH); ++ if (n < 0 || au_sbbot(sb) < n) { ++ errorfc(fc, "out of bounds, %d", bindex); ++ goto out_root; ++ } ++ ++ err = 0; ++ mod->perm = au_br_perm_val(p); ++ AuDbg("mod path %s, perm 0x%x, %s\n", ++ mod->path, mod->perm, p); ++ mod->h_root = dget(au_h_dptr(root, bindex)); ++ ++out_root: ++ aufs_read_unlock(root, !AuLock_IR); ++out: ++ AuTraceErr(err); ++ return err; ++} ++#endif ++ ++static int au_fsctx_parse_xino(struct fs_context *fc, ++ struct au_opt_xino *xino, ++ struct fs_parameter *param) ++{ ++ int err; ++ struct au_fsctx_opts *a = fc->fs_private; ++ ++ err = -ENOMEM; ++ /* will be freed by au_opts_free() */ ++ xino->path = kmemdup_nul(param->string, param->size, GFP_NOFS); ++ if (unlikely(!xino->path)) ++ goto out; ++ AuDbg("path %s\n", xino->path); ++ ++ xino->file = au_xino_create(a->sb, xino->path, /*silent*/0, ++ /*wbrtop*/0); ++ err = PTR_ERR(xino->file); ++ if (IS_ERR(xino->file)) { ++ xino->file = NULL; ++ goto out; ++ } ++ ++ err = 0; ++ if (unlikely(a->sb && xino->file->f_path.dentry->d_sb == a->sb)) { ++ err = -EINVAL; ++ errorfc(fc, "%s must be outside", xino->path); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static ++int au_fsctx_parse_xino_itrunc_path(struct fs_context *fc, ++ struct au_opt_xino_itrunc *xino_itrunc, ++ char *pathname) ++{ ++ int err; ++ aufs_bindex_t bbot, bindex; ++ struct path path; ++ struct dentry *root; ++ struct au_fsctx_opts *a = fc->fs_private; ++ ++ AuDebugOn(!a->sb); ++ ++ err = vfsub_kern_path(pathname, AuOpt_LkupDirFlags, &path); ++ if (unlikely(err)) { ++ errorfc(fc, "lookup failed %s (%d)", pathname, err); ++ goto out; ++ } ++ ++ xino_itrunc->bindex = -1; ++ root = a->sb->s_root; ++ aufs_read_lock(root, AuLock_FLUSH); ++ bbot = au_sbbot(a->sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ if (au_h_dptr(root, bindex) == path.dentry) { ++ xino_itrunc->bindex = bindex; ++ break; ++ } ++ } ++ aufs_read_unlock(root, !AuLock_IR); ++ path_put(&path); ++ ++ if (unlikely(xino_itrunc->bindex < 0)) { ++ err = -EINVAL; ++ errorfc(fc, "no such branch %s", pathname); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_fsctx_parse_xino_itrunc(struct fs_context *fc, ++ struct au_opt_xino_itrunc *xino_itrunc, ++ unsigned int bindex) ++{ ++ int err; ++ aufs_bindex_t bbot; ++ struct super_block *sb; ++ struct au_fsctx_opts *a = fc->fs_private; ++ ++ sb = a->sb; ++ AuDebugOn(!sb); ++ ++ err = 0; ++ si_noflush_read_lock(sb); ++ bbot = au_sbbot(sb); ++ si_read_unlock(sb); ++ if (bindex <= bbot) ++ xino_itrunc->bindex = bindex; ++ else { ++ err = -EINVAL; ++ errorfc(fc, "out of bounds, %u", bindex); ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_fsctx_parse_param(struct fs_context *fc, struct fs_parameter *param) ++{ ++ int err, token; ++ struct fs_parse_result result; ++ struct au_fsctx_opts *a = fc->fs_private; ++ struct au_opt *opt = a->opt; ++ ++ AuDbg("fc %p, param {key %s, string %s}\n", ++ fc, param->key, param->string); ++ err = fs_parse(fc, aufs_fsctx_paramspec, param, &result); ++ if (unlikely(err < 0)) ++ goto out; ++ token = err; ++ AuDbg("token %d, res{negated %d, uint64 %llu}\n", ++ token, result.negated, result.uint_64); ++ ++ err = -EINVAL; ++ a->skipped = 0; ++ switch (token) { ++ case Opt_br: ++ err = au_fsctx_parse_br(fc, param->string); ++ break; ++ case Opt_add: ++ err = au_fsctx_parse_add(fc, param->string); ++ break; ++ case Opt_append: ++ err = au_fsctx_parse_do_add(fc, opt, param->string, param->size, ++ /*dummy bindex*/1); ++ break; ++ case Opt_prepend: ++ err = au_fsctx_parse_do_add(fc, opt, param->string, param->size, ++ /*bindex*/0); ++ break; ++ ++ case Opt_del: ++ err = au_fsctx_parse_del(fc, &opt->del, param); ++ break; ++#if 0 /* reserved for future use */ ++ case Opt_idel: ++ if (!a->sb) { ++ err = 0; ++ a->skipped = 1; ++ break; ++ } ++ del->pathname = "(indexed)"; ++ err = au_opts_parse_idel(fc, &opt->del, result.uint_32); ++ break; ++#endif ++ ++ case Opt_mod: ++ err = au_fsctx_parse_mod(fc, &opt->mod, param); ++ break; ++#ifdef IMOD /* reserved for future use */ ++ case Opt_imod: ++ if (!a->sb) { ++ err = 0; ++ a->skipped = 1; ++ break; ++ } ++ u.mod->path = "(indexed)"; ++ err = au_opts_parse_imod(fc, &opt->mod, param->string); ++ break; ++#endif ++ ++ case Opt_xino: ++ err = au_fsctx_parse_xino(fc, &opt->xino, param); ++ break; ++ case Opt_trunc_xino_path: ++ if (!a->sb) { ++ errorfc(fc, "no such branch %s", param->string); ++ break; ++ } ++ err = au_fsctx_parse_xino_itrunc_path(fc, &opt->xino_itrunc, ++ param->string); ++ break; ++#if 0 ++ case Opt_trunc_xino_v: ++ if (!a->sb) { ++ err = 0; ++ a->skipped = 1; ++ break; ++ } ++ err = au_fsctx_parse_xino_itrunc_path(fc, &opt->xino_itrunc, ++ param->string); ++ break; ++#endif ++ case Opt_itrunc_xino: ++ if (!a->sb) { ++ errorfc(fc, "out of bounds %s", param->string); ++ break; ++ } ++ err = au_fsctx_parse_xino_itrunc(fc, &opt->xino_itrunc, ++ result.int_32); ++ break; ++ ++ case Opt_dirwh: ++ err = 0; ++ opt->dirwh = result.int_32; ++ break; ++ ++ case Opt_rdcache: ++ if (unlikely(result.int_32 > AUFS_RDCACHE_MAX)) { ++ errorfc(fc, "rdcache must be smaller than %d", ++ AUFS_RDCACHE_MAX); ++ break; ++ } ++ err = 0; ++ opt->rdcache = result.int_32; ++ break; ++ ++ case Opt_rdblk: ++ err = 0; ++ opt->rdblk = AUFS_RDBLK_DEF; ++ if (!strcmp(param->string, "def")) ++ break; ++ ++ err = kstrtoint(param->string, 0, &result.int_32); ++ if (unlikely(err)) { ++ errorfc(fc, "bad value in %s", param->key); ++ break; ++ } ++ err = -EINVAL; ++ if (unlikely(result.int_32 < 0 ++ || result.int_32 > KMALLOC_MAX_SIZE)) { ++ errorfc(fc, "bad value in %s", param->key); ++ break; ++ } ++ if (unlikely(result.int_32 && result.int_32 < NAME_MAX)) { ++ errorfc(fc, "rdblk must be larger than %d", NAME_MAX); ++ break; ++ } ++ err = 0; ++ opt->rdblk = result.int_32; ++ break; ++ ++ case Opt_rdhash: ++ err = 0; ++ opt->rdhash = AUFS_RDHASH_DEF; ++ if (!strcmp(param->string, "def")) ++ break; ++ ++ err = kstrtoint(param->string, 0, &result.int_32); ++ if (unlikely(err)) { ++ errorfc(fc, "bad value in %s", param->key); ++ break; ++ } ++ /* how about zero? */ ++ if (result.int_32 < 0 ++ || result.int_32 * sizeof(struct hlist_head) ++ > KMALLOC_MAX_SIZE) { ++ err = -EINVAL; ++ errorfc(fc, "bad integer in %s", param->key); ++ break; ++ } ++ opt->rdhash = result.int_32; ++ break; ++ ++ case Opt_diropq: ++ /* ++ * As other options, fs/aufs/opts.c can handle these strings by ++ * match_token(). But "diropq=" is deprecated now and will ++ * never have other value. So simple strcmp() is enough here. ++ */ ++ if (!strcmp(param->string, "a") || ++ !strcmp(param->string, "always")) { ++ err = 0; ++ opt->type = Opt_diropq_a; ++ } else if (!strcmp(param->string, "w") || ++ !strcmp(param->string, "whiteouted")) { ++ err = 0; ++ opt->type = Opt_diropq_w; ++ } else ++ errorfc(fc, "unknown value %s", param->string); ++ break; ++ ++ case Opt_udba: ++ opt->udba = au_udba_val(param->string); ++ if (opt->udba >= 0) ++ err = 0; ++ else ++ errorf(fc, "wrong value, %s", param->string); ++ break; ++ ++ case Opt_wbr_create: ++ opt->wbr_create.wbr_create ++ = au_wbr_create_val(param->string, &opt->wbr_create); ++ if (opt->wbr_create.wbr_create >= 0) ++ err = 0; ++ else ++ errorf(fc, "wrong value, %s", param->key); ++ break; ++ ++ case Opt_wbr_copyup: ++ opt->wbr_copyup = au_wbr_copyup_val(param->string); ++ if (opt->wbr_copyup >= 0) ++ err = 0; ++ else ++ errorfc(fc, "wrong value, %s", param->key); ++ break; ++ ++ case Opt_fhsm_sec: ++ if (unlikely(result.int_32 < 0)) { ++ errorfc(fc, "bad integer in %s\n", param->key); ++ break; ++ } ++ err = 0; ++ if (sysaufs_brs) ++ opt->fhsm_second = result.int_32; ++ else ++ warnfc(fc, "ignored %s %s", param->key, param->string); ++ break; ++ ++ /* simple true/false flag */ ++#define au_fsctx_TF(name) \ ++ case Opt_##name: \ ++ err = 0; \ ++ opt->tf = !result.negated; \ ++ break; ++ au_fsctx_TF(trunc_xino); ++ au_fsctx_TF(trunc_xib); ++ au_fsctx_TF(dirperm1); ++ au_fsctx_TF(plink); ++ au_fsctx_TF(shwh); ++ au_fsctx_TF(dio); ++ au_fsctx_TF(warn_perm); ++ au_fsctx_TF(verbose); ++ au_fsctx_TF(sum); ++ au_fsctx_TF(dirren); ++ au_fsctx_TF(acl); ++#undef au_fsctx_TF ++ ++ case Opt_noverbose: ++ err = 0; ++ opt->type = Opt_verbose; ++ opt->tf = false; ++ break; ++ ++ case Opt_noxino: ++ fallthrough; ++ case Opt_list_plink: ++ fallthrough; ++ case Opt_wsum: ++ err = 0; ++ break; ++ ++ case Opt_ignore: ++ warnfc(fc, "ignored %s", param->key); ++ fallthrough; ++ case Opt_ignore_silent: ++ a->skipped = 1; ++ err = 0; ++ break; ++ default: ++ a->skipped = 1; ++ err = -ENOPARAM; ++ break; ++ } ++ if (unlikely(err)) ++ goto out; ++ if (a->skipped) ++ goto out; ++ ++ switch (token) { ++ case Opt_br: ++ fallthrough; ++ case Opt_noverbose: ++ fallthrough; ++ case Opt_diropq: ++ break; ++ default: ++ opt->type = token; ++ break; ++ } ++ opt++; ++ if (unlikely(opt > a->opt_tail)) { ++ err = -E2BIG; ++ opt--; ++ } ++ opt->type = Opt_tail; ++ a->opt = opt; ++ ++out: ++ return err; ++} ++ ++/* ++ * these options accept both 'name=val' and 'name:val' form. ++ * some accept optional '=' in its value. ++ * eg. br:/br1=rw:/br2=ro and br=/br1=rw:/br2=ro ++ */ ++static inline unsigned int is_colonopt(char *str) ++{ ++#define do_test(name) \ ++ if (!strncmp(str, name ":", sizeof(name))) \ ++ return sizeof(name) - 1; ++ do_test("br"); ++ do_test("add"); ++ do_test("ins"); ++ do_test("append"); ++ do_test("prepend"); ++ do_test("del"); ++ /* do_test("idel"); */ ++ do_test("mod"); ++ /* do_test("imod"); */ ++#undef do_test ++ ++ return 0; ++} ++ ++static int au_fsctx_parse_monolithic(struct fs_context *fc, void *data) ++{ ++ int err; ++ unsigned int u; ++ char *str; ++ struct au_fsctx_opts *a = fc->fs_private; ++ ++ str = data; ++ AuDbg("str %s\n", str); ++ while (str) { ++ u = is_colonopt(str); ++ if (u) ++ str[u] = '='; ++ str = strchr(str, ','); ++ if (!str) ++ break; ++ str++; ++ } ++ str = data; ++ AuDbg("str %s\n", str); ++ ++ err = generic_parse_monolithic(fc, str); ++ AuTraceErr(err); ++ au_fsctx_dump(&a->opts); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_fsctx_opts_free(struct au_opts *opts) ++{ ++ struct au_opt *opt; ++ ++ opt = opts->opt; ++ while (opt->type != Opt_tail) { ++ switch (opt->type) { ++ case Opt_add: ++ fallthrough; ++ case Opt_append: ++ fallthrough; ++ case Opt_prepend: ++ kfree(opt->add.pathname); ++ path_put(&opt->add.path); ++ break; ++ case Opt_del: ++ kfree(opt->del.pathname); ++ fallthrough; ++ case Opt_idel: ++ path_put(&opt->del.h_path); ++ break; ++ case Opt_mod: ++ kfree(opt->mod.path); ++ fallthrough; ++ case Opt_imod: ++ dput(opt->mod.h_root); ++ break; ++ case Opt_xino: ++ kfree(opt->xino.path); ++ fput(opt->xino.file); ++ break; ++ } ++ opt++; ++ } ++} ++ ++static void au_fsctx_free(struct fs_context *fc) ++{ ++ struct au_fsctx_opts *a = fc->fs_private; ++ ++ /* fs_type=%p, root=%pD */ ++ AuDbg("fc %p{sb_flags 0x%x, sb_flags_mask 0x%x, purpose %u\n", ++ fc, fc->sb_flags, fc->sb_flags_mask, fc->purpose); ++ ++ kobject_put(&a->sbinfo->si_kobj); ++ au_fsctx_opts_free(&a->opts); ++ free_page((unsigned long)a->opts.opt); ++ au_kfree_rcu(a); ++} ++ ++static const struct fs_context_operations au_fsctx_ops = { ++ .free = au_fsctx_free, ++ .parse_param = au_fsctx_parse_param, ++ .parse_monolithic = au_fsctx_parse_monolithic, ++ .get_tree = au_fsctx_get_tree, ++ .reconfigure = au_fsctx_reconfigure ++ /* ++ * nfs4 requires ->dup()? No. ++ * I don't know what is this ->dup() for. ++ */ ++}; ++ ++int aufs_fsctx_init(struct fs_context *fc) ++{ ++ int err; ++ struct au_fsctx_opts *a; ++ ++ /* fs_type=%p, root=%pD */ ++ AuDbg("fc %p{sb_flags 0x%x, sb_flags_mask 0x%x, purpose %u\n", ++ fc, fc->sb_flags, fc->sb_flags_mask, fc->purpose); ++ ++ /* they will be freed by au_fsctx_free() */ ++ err = -ENOMEM; ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ a->bindex = 0; ++ a->opts.opt = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!a->opts.opt)) ++ goto out_a; ++ a->opt = a->opts.opt; ++ a->opt->type = Opt_tail; ++ a->opts.max_opt = PAGE_SIZE / sizeof(*a->opts.opt); ++ a->opt_tail = a->opt + a->opts.max_opt - 1; ++ a->opts.sb_flags = fc->sb_flags; ++ ++ a->sb = NULL; ++ if (fc->root) { ++ AuDebugOn(fc->purpose != FS_CONTEXT_FOR_RECONFIGURE); ++ a->opts.flags = AuOpts_REMOUNT; ++ a->sb = fc->root->d_sb; ++ a->sbinfo = au_sbi(a->sb); ++ kobject_get(&a->sbinfo->si_kobj); ++ } else { ++ a->sbinfo = au_si_alloc(a->sb); ++ AuDebugOn(!a->sbinfo); ++ err = PTR_ERR(a->sbinfo); ++ if (IS_ERR(a->sbinfo)) ++ goto out_opt; ++ au_rw_write_unlock(&a->sbinfo->si_rwsem); ++ } ++ ++ err = 0; ++ fc->fs_private = a; ++ fc->ops = &au_fsctx_ops; ++ goto out; /* success */ ++ ++out_opt: ++ free_page((unsigned long)a->opts.opt); ++out_a: ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} +diff -Naur null/fs/aufs/fstype.h linux-5.15.36/fs/aufs/fstype.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/fstype.h 2022-05-10 16:51:39.871744219 +0300 +@@ -0,0 +1,401 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * judging filesystem type ++ */ ++ ++#ifndef __AUFS_FSTYPE_H__ ++#define __AUFS_FSTYPE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++ ++static inline int au_test_aufs(struct super_block *sb) ++{ ++ return sb->s_magic == AUFS_SUPER_MAGIC; ++} ++ ++static inline const char *au_sbtype(struct super_block *sb) ++{ ++ return sb->s_type->name; ++} ++ ++static inline int au_test_iso9660(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_ISO9660_FS) ++ return sb->s_magic == ISOFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_romfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_ROMFS_FS) ++ return sb->s_magic == ROMFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_cramfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_CRAMFS) ++ return sb->s_magic == CRAMFS_MAGIC; ++#endif ++ return 0; ++} ++ ++static inline int au_test_nfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_NFS_FS) ++ return sb->s_magic == NFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_fuse(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_FUSE_FS) ++ return sb->s_magic == FUSE_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_xfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_XFS_FS) ++ return sb->s_magic == XFS_SB_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_tmpfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_TMPFS ++ return sb->s_magic == TMPFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_ecryptfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_ECRYPT_FS) ++ return !strcmp(au_sbtype(sb), "ecryptfs"); ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_ramfs(struct super_block *sb) ++{ ++ return sb->s_magic == RAMFS_MAGIC; ++} ++ ++static inline int au_test_ubifs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_UBIFS_FS) ++ return sb->s_magic == UBIFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_procfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_PROC_FS ++ return sb->s_magic == PROC_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_sysfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_SYSFS ++ return sb->s_magic == SYSFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_configfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_CONFIGFS_FS) ++ return sb->s_magic == CONFIGFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_minix(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_MINIX_FS) ++ return sb->s_magic == MINIX3_SUPER_MAGIC ++ || sb->s_magic == MINIX2_SUPER_MAGIC ++ || sb->s_magic == MINIX2_SUPER_MAGIC2 ++ || sb->s_magic == MINIX_SUPER_MAGIC ++ || sb->s_magic == MINIX_SUPER_MAGIC2; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_fat(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_FAT_FS) ++ return sb->s_magic == MSDOS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_msdos(struct super_block *sb) ++{ ++ return au_test_fat(sb); ++} ++ ++static inline int au_test_vfat(struct super_block *sb) ++{ ++ return au_test_fat(sb); ++} ++ ++static inline int au_test_securityfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_SECURITYFS ++ return sb->s_magic == SECURITYFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_squashfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_SQUASHFS) ++ return sb->s_magic == SQUASHFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_btrfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_BTRFS_FS) ++ return sb->s_magic == BTRFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_xenfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_XENFS) ++ return sb->s_magic == XENFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_debugfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_DEBUG_FS ++ return sb->s_magic == DEBUGFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_nilfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_NILFS) ++ return sb->s_magic == NILFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_hfsplus(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_HFSPLUS_FS) ++ return sb->s_magic == HFSPLUS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * they can't be an aufs branch. ++ */ ++static inline int au_test_fs_unsuppoted(struct super_block *sb) ++{ ++ return ++#ifndef CONFIG_AUFS_BR_RAMFS ++ au_test_ramfs(sb) || ++#endif ++ au_test_procfs(sb) ++ || au_test_sysfs(sb) ++ || au_test_configfs(sb) ++ || au_test_debugfs(sb) ++ || au_test_securityfs(sb) ++ || au_test_xenfs(sb) ++ || au_test_ecryptfs(sb) ++ /* || !strcmp(au_sbtype(sb), "unionfs") */ ++ || au_test_aufs(sb); /* will be supported in next version */ ++} ++ ++static inline int au_test_fs_remote(struct super_block *sb) ++{ ++ return !au_test_tmpfs(sb) ++#ifdef CONFIG_AUFS_BR_RAMFS ++ && !au_test_ramfs(sb) ++#endif ++ && !(sb->s_type->fs_flags & FS_REQUIRES_DEV); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * Note: these functions (below) are created after reading ->getattr() in all ++ * filesystems under linux/fs. it means we have to do so in every update... ++ */ ++ ++/* ++ * some filesystems require getattr to refresh the inode attributes before ++ * referencing. ++ * in most cases, we can rely on the inode attribute in NFS (or every remote fs) ++ * and leave the work for d_revalidate() ++ */ ++static inline int au_test_fs_refresh_iattr(struct super_block *sb) ++{ ++ return au_test_nfs(sb) ++ || au_test_fuse(sb) ++ /* || au_test_btrfs(sb) */ /* untested */ ++ ; ++} ++ ++/* ++ * filesystems which don't maintain i_size or i_blocks. ++ */ ++static inline int au_test_fs_bad_iattr_size(struct super_block *sb) ++{ ++ return au_test_xfs(sb) ++ || au_test_btrfs(sb) ++ || au_test_ubifs(sb) ++ || au_test_hfsplus(sb) /* maintained, but incorrect */ ++ /* || au_test_minix(sb) */ /* untested */ ++ ; ++} ++ ++/* ++ * filesystems which don't store the correct value in some of their inode ++ * attributes. ++ */ ++static inline int au_test_fs_bad_iattr(struct super_block *sb) ++{ ++ return au_test_fs_bad_iattr_size(sb) ++ || au_test_fat(sb) ++ || au_test_msdos(sb) ++ || au_test_vfat(sb); ++} ++ ++/* they don't check i_nlink in link(2) */ ++static inline int au_test_fs_no_limit_nlink(struct super_block *sb) ++{ ++ return au_test_tmpfs(sb) ++#ifdef CONFIG_AUFS_BR_RAMFS ++ || au_test_ramfs(sb) ++#endif ++ || au_test_ubifs(sb) ++ || au_test_hfsplus(sb); ++} ++ ++/* ++ * filesystems which sets S_NOATIME and S_NOCMTIME. ++ */ ++static inline int au_test_fs_notime(struct super_block *sb) ++{ ++ return au_test_nfs(sb) ++ || au_test_fuse(sb) ++ || au_test_ubifs(sb) ++ ; ++} ++ ++/* temporary support for i#1 in cramfs */ ++static inline int au_test_fs_unique_ino(struct inode *inode) ++{ ++ if (au_test_cramfs(inode->i_sb)) ++ return inode->i_ino != 1; ++ return 1; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * the filesystem where the xino files placed must support i/o after unlink and ++ * maintain i_size and i_blocks. ++ */ ++static inline int au_test_fs_bad_xino(struct super_block *sb) ++{ ++ return au_test_fs_remote(sb) ++ || au_test_fs_bad_iattr_size(sb) ++ /* don't want unnecessary work for xino */ ++ || au_test_aufs(sb) ++ || au_test_ecryptfs(sb) ++ || au_test_nilfs(sb); ++} ++ ++static inline int au_test_fs_trunc_xino(struct super_block *sb) ++{ ++ return au_test_tmpfs(sb) ++ || au_test_ramfs(sb); ++} ++ ++/* ++ * test if the @sb is real-readonly. ++ */ ++static inline int au_test_fs_rr(struct super_block *sb) ++{ ++ return au_test_squashfs(sb) ++ || au_test_iso9660(sb) ++ || au_test_cramfs(sb) ++ || au_test_romfs(sb); ++} ++ ++/* ++ * test if the @inode is nfs with 'noacl' option ++ * NFS always sets SB_POSIXACL regardless its mount option 'noacl.' ++ */ ++static inline int au_test_nfs_noacl(struct inode *inode) ++{ ++ return au_test_nfs(inode->i_sb) ++ /* && IS_POSIXACL(inode) */ ++ && !nfs_server_capable(inode, NFS_CAP_ACLS); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_FSTYPE_H__ */ +diff -Naur null/fs/aufs/hbl.h linux-5.15.36/fs/aufs/hbl.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/hbl.h 2022-05-10 16:51:39.871744219 +0300 +@@ -0,0 +1,65 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2017-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * helpers for hlist_bl.h ++ */ ++ ++#ifndef __AUFS_HBL_H__ ++#define __AUFS_HBL_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++static inline void au_hbl_add(struct hlist_bl_node *node, ++ struct hlist_bl_head *hbl) ++{ ++ hlist_bl_lock(hbl); ++ hlist_bl_add_head(node, hbl); ++ hlist_bl_unlock(hbl); ++} ++ ++static inline void au_hbl_del(struct hlist_bl_node *node, ++ struct hlist_bl_head *hbl) ++{ ++ hlist_bl_lock(hbl); ++ hlist_bl_del(node); ++ hlist_bl_unlock(hbl); ++} ++ ++#define au_hbl_for_each(pos, head) \ ++ for (pos = hlist_bl_first(head); \ ++ pos; \ ++ pos = pos->next) ++ ++static inline unsigned long au_hbl_count(struct hlist_bl_head *hbl) ++{ ++ unsigned long cnt; ++ struct hlist_bl_node *pos; ++ ++ cnt = 0; ++ hlist_bl_lock(hbl); ++ au_hbl_for_each(pos, hbl) ++ cnt++; ++ hlist_bl_unlock(hbl); ++ return cnt; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_HBL_H__ */ +diff -Naur null/fs/aufs/hfsnotify.c linux-5.15.36/fs/aufs/hfsnotify.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/hfsnotify.c 2022-05-10 16:51:39.871744219 +0300 +@@ -0,0 +1,288 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * fsnotify for the lower directories ++ */ ++ ++#include "aufs.h" ++ ++/* FS_IN_IGNORED is unnecessary */ ++static const __u32 AuHfsnMask = (FS_MOVED_TO | FS_MOVED_FROM | FS_DELETE ++ | FS_CREATE | FS_EVENT_ON_CHILD); ++static DECLARE_WAIT_QUEUE_HEAD(au_hfsn_wq); ++static __cacheline_aligned_in_smp atomic64_t au_hfsn_ifree = ATOMIC64_INIT(0); ++ ++static void au_hfsn_free_mark(struct fsnotify_mark *mark) ++{ ++ struct au_hnotify *hn = container_of(mark, struct au_hnotify, ++ hn_mark); ++ /* AuDbg("here\n"); */ ++ au_cache_free_hnotify(hn); ++ smp_mb__before_atomic(); /* for atomic64_dec */ ++ if (atomic64_dec_and_test(&au_hfsn_ifree)) ++ wake_up(&au_hfsn_wq); ++} ++ ++static int au_hfsn_alloc(struct au_hinode *hinode) ++{ ++ int err; ++ struct au_hnotify *hn; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct fsnotify_mark *mark; ++ aufs_bindex_t bindex; ++ ++ hn = hinode->hi_notify; ++ sb = hn->hn_aufs_inode->i_sb; ++ bindex = au_br_index(sb, hinode->hi_id); ++ br = au_sbr(sb, bindex); ++ AuDebugOn(!br->br_hfsn); ++ ++ mark = &hn->hn_mark; ++ fsnotify_init_mark(mark, br->br_hfsn->hfsn_group); ++ mark->mask = AuHfsnMask; ++ /* ++ * by udba rename or rmdir, aufs assign a new inode to the known ++ * h_inode, so specify 1 to allow dups. ++ */ ++ lockdep_off(); ++ err = fsnotify_add_inode_mark(mark, hinode->hi_inode, /*allow_dups*/1); ++ lockdep_on(); ++ ++ return err; ++} ++ ++static int au_hfsn_free(struct au_hinode *hinode, struct au_hnotify *hn) ++{ ++ struct fsnotify_mark *mark; ++ unsigned long long ull; ++ struct fsnotify_group *group; ++ ++ ull = atomic64_inc_return(&au_hfsn_ifree); ++ BUG_ON(!ull); ++ ++ mark = &hn->hn_mark; ++ spin_lock(&mark->lock); ++ group = mark->group; ++ fsnotify_get_group(group); ++ spin_unlock(&mark->lock); ++ lockdep_off(); ++ fsnotify_destroy_mark(mark, group); ++ fsnotify_put_mark(mark); ++ fsnotify_put_group(group); ++ lockdep_on(); ++ ++ /* free hn by myself */ ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_hfsn_ctl(struct au_hinode *hinode, int do_set) ++{ ++ struct fsnotify_mark *mark; ++ ++ mark = &hinode->hi_notify->hn_mark; ++ spin_lock(&mark->lock); ++ if (do_set) { ++ AuDebugOn(mark->mask & AuHfsnMask); ++ mark->mask |= AuHfsnMask; ++ } else { ++ AuDebugOn(!(mark->mask & AuHfsnMask)); ++ mark->mask &= ~AuHfsnMask; ++ } ++ spin_unlock(&mark->lock); ++ /* fsnotify_recalc_inode_mask(hinode->hi_inode); */ ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* #define AuDbgHnotify */ ++#ifdef AuDbgHnotify ++static char *au_hfsn_name(u32 mask) ++{ ++#ifdef CONFIG_AUFS_DEBUG ++#define test_ret(flag) \ ++ do { \ ++ if (mask & flag) \ ++ return #flag; \ ++ } while (0) ++ test_ret(FS_ACCESS); ++ test_ret(FS_MODIFY); ++ test_ret(FS_ATTRIB); ++ test_ret(FS_CLOSE_WRITE); ++ test_ret(FS_CLOSE_NOWRITE); ++ test_ret(FS_OPEN); ++ test_ret(FS_MOVED_FROM); ++ test_ret(FS_MOVED_TO); ++ test_ret(FS_CREATE); ++ test_ret(FS_DELETE); ++ test_ret(FS_DELETE_SELF); ++ test_ret(FS_MOVE_SELF); ++ test_ret(FS_UNMOUNT); ++ test_ret(FS_Q_OVERFLOW); ++ test_ret(FS_IN_IGNORED); ++ test_ret(FS_ISDIR); ++ test_ret(FS_IN_ONESHOT); ++ test_ret(FS_EVENT_ON_CHILD); ++ return ""; ++#undef test_ret ++#else ++ return "??"; ++#endif ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_hfsn_free_group(struct fsnotify_group *group) ++{ ++ struct au_br_hfsnotify *hfsn = group->private; ++ ++ /* AuDbg("here\n"); */ ++ au_kfree_try_rcu(hfsn); ++} ++ ++static int au_hfsn_handle_event(struct fsnotify_group *group, ++ u32 mask, const void *data, int data_type, ++ struct inode *dir, ++ const struct qstr *file_name, u32 cookie, ++ struct fsnotify_iter_info *iter_info) ++{ ++ int err; ++ struct au_hnotify *hnotify; ++ struct inode *h_dir, *h_inode; ++ struct fsnotify_mark *inode_mark; ++ ++ AuDebugOn(data_type != FSNOTIFY_EVENT_INODE); ++ ++ err = 0; ++ /* if FS_UNMOUNT happens, there must be another bug */ ++ AuDebugOn(mask & FS_UNMOUNT); ++ if (mask & (FS_IN_IGNORED | FS_UNMOUNT)) ++ goto out; ++ ++ h_dir = dir; ++ h_inode = NULL; ++#ifdef AuDbgHnotify ++ au_debug_on(); ++ if (1 || h_child_qstr.len != sizeof(AUFS_XINO_FNAME) - 1 ++ || strncmp(h_child_qstr.name, AUFS_XINO_FNAME, h_child_qstr.len)) { ++ AuDbg("i%lu, mask 0x%x %s, hcname %.*s, hi%lu\n", ++ h_dir->i_ino, mask, au_hfsn_name(mask), ++ AuLNPair(&h_child_qstr), h_inode ? h_inode->i_ino : 0); ++ /* WARN_ON(1); */ ++ } ++ au_debug_off(); ++#endif ++ ++ inode_mark = fsnotify_iter_inode_mark(iter_info); ++ AuDebugOn(!inode_mark); ++ hnotify = container_of(inode_mark, struct au_hnotify, hn_mark); ++ err = au_hnotify(h_dir, hnotify, mask, file_name, h_inode); ++ ++out: ++ return err; ++} ++ ++static struct fsnotify_ops au_hfsn_ops = { ++ .handle_event = au_hfsn_handle_event, ++ .free_group_priv = au_hfsn_free_group, ++ .free_mark = au_hfsn_free_mark ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_hfsn_fin_br(struct au_branch *br) ++{ ++ struct au_br_hfsnotify *hfsn; ++ ++ hfsn = br->br_hfsn; ++ if (hfsn) { ++ lockdep_off(); ++ fsnotify_put_group(hfsn->hfsn_group); ++ lockdep_on(); ++ } ++} ++ ++static int au_hfsn_init_br(struct au_branch *br, int perm) ++{ ++ int err; ++ struct fsnotify_group *group; ++ struct au_br_hfsnotify *hfsn; ++ ++ err = 0; ++ br->br_hfsn = NULL; ++ if (!au_br_hnotifyable(perm)) ++ goto out; ++ ++ err = -ENOMEM; ++ hfsn = kmalloc(sizeof(*hfsn), GFP_NOFS); ++ if (unlikely(!hfsn)) ++ goto out; ++ ++ err = 0; ++ group = fsnotify_alloc_group(&au_hfsn_ops); ++ if (IS_ERR(group)) { ++ err = PTR_ERR(group); ++ pr_err("fsnotify_alloc_group() failed, %d\n", err); ++ goto out_hfsn; ++ } ++ ++ group->private = hfsn; ++ hfsn->hfsn_group = group; ++ br->br_hfsn = hfsn; ++ goto out; /* success */ ++ ++out_hfsn: ++ au_kfree_try_rcu(hfsn); ++out: ++ return err; ++} ++ ++static int au_hfsn_reset_br(unsigned int udba, struct au_branch *br, int perm) ++{ ++ int err; ++ ++ err = 0; ++ if (!br->br_hfsn) ++ err = au_hfsn_init_br(br, perm); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_hfsn_fin(void) ++{ ++ AuDbg("au_hfsn_ifree %lld\n", (long long)atomic64_read(&au_hfsn_ifree)); ++ wait_event(au_hfsn_wq, !atomic64_read(&au_hfsn_ifree)); ++} ++ ++const struct au_hnotify_op au_hnotify_op = { ++ .ctl = au_hfsn_ctl, ++ .alloc = au_hfsn_alloc, ++ .free = au_hfsn_free, ++ ++ .fin = au_hfsn_fin, ++ ++ .reset_br = au_hfsn_reset_br, ++ .fin_br = au_hfsn_fin_br, ++ .init_br = au_hfsn_init_br ++}; +diff -Naur null/fs/aufs/hfsplus.c linux-5.15.36/fs/aufs/hfsplus.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/hfsplus.c 2022-05-10 16:51:39.872744219 +0300 +@@ -0,0 +1,60 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2010-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * special support for filesystems which acquires an inode mutex ++ * at final closing a file, eg, hfsplus. ++ * ++ * This trick is very simple and stupid, just to open the file before really ++ * necessary open to tell hfsplus that this is not the final closing. ++ * The caller should call au_h_open_pre() after acquiring the inode mutex, ++ * and au_h_open_post() after releasing it. ++ */ ++ ++#include "aufs.h" ++ ++struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex, ++ int force_wr) ++{ ++ struct file *h_file; ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ AuDebugOn(!h_dentry); ++ AuDebugOn(d_is_negative(h_dentry)); ++ ++ h_file = NULL; ++ if (au_test_hfsplus(h_dentry->d_sb) ++ && d_is_reg(h_dentry)) ++ h_file = au_h_open(dentry, bindex, ++ O_RDONLY | O_NOATIME | O_LARGEFILE, ++ /*file*/NULL, force_wr); ++ return h_file; ++} ++ ++void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex, ++ struct file *h_file) ++{ ++ struct au_branch *br; ++ ++ if (h_file) { ++ fput(h_file); ++ br = au_sbr(dentry->d_sb, bindex); ++ au_lcnt_dec(&br->br_nfiles); ++ } ++} +diff -Naur null/fs/aufs/hnotify.c linux-5.15.36/fs/aufs/hnotify.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/hnotify.c 2022-05-10 16:51:39.872744219 +0300 +@@ -0,0 +1,715 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * abstraction to notify the direct changes on lower directories ++ */ ++ ++/* #include */ ++#include "aufs.h" ++ ++int au_hn_alloc(struct au_hinode *hinode, struct inode *inode) ++{ ++ int err; ++ struct au_hnotify *hn; ++ ++ err = -ENOMEM; ++ hn = au_cache_alloc_hnotify(); ++ if (hn) { ++ hn->hn_aufs_inode = inode; ++ hinode->hi_notify = hn; ++ err = au_hnotify_op.alloc(hinode); ++ AuTraceErr(err); ++ if (unlikely(err)) { ++ hinode->hi_notify = NULL; ++ au_cache_free_hnotify(hn); ++ /* ++ * The upper dir was removed by udba, but the same named ++ * dir left. In this case, aufs assigns a new inode ++ * number and set the monitor again. ++ * For the lower dir, the old monitor is still left. ++ */ ++ if (err == -EEXIST) ++ err = 0; ++ } ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_hn_free(struct au_hinode *hinode) ++{ ++ struct au_hnotify *hn; ++ ++ hn = hinode->hi_notify; ++ if (hn) { ++ hinode->hi_notify = NULL; ++ if (au_hnotify_op.free(hinode, hn)) ++ au_cache_free_hnotify(hn); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_hn_ctl(struct au_hinode *hinode, int do_set) ++{ ++ if (hinode->hi_notify) ++ au_hnotify_op.ctl(hinode, do_set); ++} ++ ++void au_hn_reset(struct inode *inode, unsigned int flags) ++{ ++ aufs_bindex_t bindex, bbot; ++ struct inode *hi; ++ struct dentry *iwhdentry; ++ ++ bbot = au_ibbot(inode); ++ for (bindex = au_ibtop(inode); bindex <= bbot; bindex++) { ++ hi = au_h_iptr(inode, bindex); ++ if (!hi) ++ continue; ++ ++ /* inode_lock_nested(hi, AuLsc_I_CHILD); */ ++ iwhdentry = au_hi_wh(inode, bindex); ++ if (iwhdentry) ++ dget(iwhdentry); ++ au_igrab(hi); ++ au_set_h_iptr(inode, bindex, NULL, 0); ++ au_set_h_iptr(inode, bindex, au_igrab(hi), ++ flags & ~AuHi_XINO); ++ iput(hi); ++ dput(iwhdentry); ++ /* inode_unlock(hi); */ ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int hn_xino(struct inode *inode, struct inode *h_inode) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot, bfound, btop; ++ struct inode *h_i; ++ ++ err = 0; ++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { ++ pr_warn("branch root dir was changed\n"); ++ goto out; ++ } ++ ++ bfound = -1; ++ bbot = au_ibbot(inode); ++ btop = au_ibtop(inode); ++#if 0 /* reserved for future use */ ++ if (bindex == bbot) { ++ /* keep this ino in rename case */ ++ goto out; ++ } ++#endif ++ for (bindex = btop; bindex <= bbot; bindex++) ++ if (au_h_iptr(inode, bindex) == h_inode) { ++ bfound = bindex; ++ break; ++ } ++ if (bfound < 0) ++ goto out; ++ ++ for (bindex = btop; bindex <= bbot; bindex++) { ++ h_i = au_h_iptr(inode, bindex); ++ if (!h_i) ++ continue; ++ ++ err = au_xino_write(inode->i_sb, bindex, h_i->i_ino, /*ino*/0); ++ /* ignore this error */ ++ /* bad action? */ ++ } ++ ++ /* children inode number will be broken */ ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int hn_gen_tree(struct dentry *dentry) ++{ ++ int err, i, j, ndentry; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, dentry, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ for (i = 0; i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ ndentry = dpage->ndentry; ++ for (j = 0; j < ndentry; j++) { ++ struct dentry *d; ++ ++ d = dentries[j]; ++ if (IS_ROOT(d)) ++ continue; ++ ++ au_digen_dec(d); ++ if (d_really_is_positive(d)) ++ /* todo: reset children xino? ++ cached children only? */ ++ au_iigen_dec(d_inode(d)); ++ } ++ } ++ ++out_dpages: ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++/* ++ * return 0 if processed. ++ */ ++static int hn_gen_by_inode(char *name, unsigned int nlen, struct inode *inode, ++ const unsigned int isdir) ++{ ++ int err; ++ struct dentry *d; ++ struct qstr *dname; ++ ++ err = 1; ++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { ++ pr_warn("branch root dir was changed\n"); ++ err = 0; ++ goto out; ++ } ++ ++ if (!isdir) { ++ AuDebugOn(!name); ++ au_iigen_dec(inode); ++ spin_lock(&inode->i_lock); ++ hlist_for_each_entry(d, &inode->i_dentry, d_u.d_alias) { ++ spin_lock(&d->d_lock); ++ dname = &d->d_name; ++ if (dname->len != nlen ++ && memcmp(dname->name, name, nlen)) { ++ spin_unlock(&d->d_lock); ++ continue; ++ } ++ err = 0; ++ au_digen_dec(d); ++ spin_unlock(&d->d_lock); ++ break; ++ } ++ spin_unlock(&inode->i_lock); ++ } else { ++ au_fset_si(au_sbi(inode->i_sb), FAILED_REFRESH_DIR); ++ d = d_find_any_alias(inode); ++ if (!d) { ++ au_iigen_dec(inode); ++ goto out; ++ } ++ ++ spin_lock(&d->d_lock); ++ dname = &d->d_name; ++ if (dname->len == nlen && !memcmp(dname->name, name, nlen)) { ++ spin_unlock(&d->d_lock); ++ err = hn_gen_tree(d); ++ spin_lock(&d->d_lock); ++ } ++ spin_unlock(&d->d_lock); ++ dput(d); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int hn_gen_by_name(struct dentry *dentry, const unsigned int isdir) ++{ ++ int err; ++ ++ if (IS_ROOT(dentry)) { ++ pr_warn("branch root dir was changed\n"); ++ return 0; ++ } ++ ++ err = 0; ++ if (!isdir) { ++ au_digen_dec(dentry); ++ if (d_really_is_positive(dentry)) ++ au_iigen_dec(d_inode(dentry)); ++ } else { ++ au_fset_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR); ++ if (d_really_is_positive(dentry)) ++ err = hn_gen_tree(dentry); ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* hnotify job flags */ ++#define AuHnJob_XINO0 1 ++#define AuHnJob_GEN (1 << 1) ++#define AuHnJob_DIRENT (1 << 2) ++#define AuHnJob_ISDIR (1 << 3) ++#define AuHnJob_TRYXINO0 (1 << 4) ++#define AuHnJob_MNTPNT (1 << 5) ++#define au_ftest_hnjob(flags, name) ((flags) & AuHnJob_##name) ++#define au_fset_hnjob(flags, name) \ ++ do { (flags) |= AuHnJob_##name; } while (0) ++#define au_fclr_hnjob(flags, name) \ ++ do { (flags) &= ~AuHnJob_##name; } while (0) ++ ++enum { ++ AuHn_CHILD, ++ AuHn_PARENT, ++ AuHnLast ++}; ++ ++struct au_hnotify_args { ++ struct inode *h_dir, *dir, *h_child_inode; ++ u32 mask; ++ unsigned int flags[AuHnLast]; ++ unsigned int h_child_nlen; ++ char h_child_name[]; ++}; ++ ++struct hn_job_args { ++ unsigned int flags; ++ struct inode *inode, *h_inode, *dir, *h_dir; ++ struct dentry *dentry; ++ char *h_name; ++ int h_nlen; ++}; ++ ++static int hn_job(struct hn_job_args *a) ++{ ++ const unsigned int isdir = au_ftest_hnjob(a->flags, ISDIR); ++ int e; ++ ++ /* reset xino */ ++ if (au_ftest_hnjob(a->flags, XINO0) && a->inode) ++ hn_xino(a->inode, a->h_inode); /* ignore this error */ ++ ++ if (au_ftest_hnjob(a->flags, TRYXINO0) ++ && a->inode ++ && a->h_inode) { ++ inode_lock_shared_nested(a->h_inode, AuLsc_I_CHILD); ++ if (!a->h_inode->i_nlink ++ && !(a->h_inode->i_state & I_LINKABLE)) ++ hn_xino(a->inode, a->h_inode); /* ignore this error */ ++ inode_unlock_shared(a->h_inode); ++ } ++ ++ /* make the generation obsolete */ ++ if (au_ftest_hnjob(a->flags, GEN)) { ++ e = -1; ++ if (a->inode) ++ e = hn_gen_by_inode(a->h_name, a->h_nlen, a->inode, ++ isdir); ++ if (e && a->dentry) ++ hn_gen_by_name(a->dentry, isdir); ++ /* ignore this error */ ++ } ++ ++ /* make dir entries obsolete */ ++ if (au_ftest_hnjob(a->flags, DIRENT) && a->inode) { ++ struct au_vdir *vdir; ++ ++ vdir = au_ivdir(a->inode); ++ if (vdir) ++ vdir->vd_jiffy = 0; ++ /* IMustLock(a->inode); */ ++ /* inode_inc_iversion(a->inode); */ ++ } ++ ++ /* can do nothing but warn */ ++ if (au_ftest_hnjob(a->flags, MNTPNT) ++ && a->dentry ++ && d_mountpoint(a->dentry)) ++ pr_warn("mount-point %pd is removed or renamed\n", a->dentry); ++ ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry *lookup_wlock_by_name(char *name, unsigned int nlen, ++ struct inode *dir) ++{ ++ struct dentry *dentry, *d, *parent; ++ struct qstr *dname; ++ ++ parent = d_find_any_alias(dir); ++ if (!parent) ++ return NULL; ++ ++ dentry = NULL; ++ spin_lock(&parent->d_lock); ++ list_for_each_entry(d, &parent->d_subdirs, d_child) { ++ /* AuDbg("%pd\n", d); */ ++ spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED); ++ dname = &d->d_name; ++ if (dname->len != nlen || memcmp(dname->name, name, nlen)) ++ goto cont_unlock; ++ if (au_di(d)) ++ au_digen_dec(d); ++ else ++ goto cont_unlock; ++ if (au_dcount(d) > 0) { ++ dentry = dget_dlock(d); ++ spin_unlock(&d->d_lock); ++ break; ++ } ++ ++cont_unlock: ++ spin_unlock(&d->d_lock); ++ } ++ spin_unlock(&parent->d_lock); ++ dput(parent); ++ ++ if (dentry) ++ di_write_lock_child(dentry); ++ ++ return dentry; ++} ++ ++static struct inode *lookup_wlock_by_ino(struct super_block *sb, ++ aufs_bindex_t bindex, ino_t h_ino) ++{ ++ struct inode *inode; ++ ino_t ino; ++ int err; ++ ++ inode = NULL; ++ err = au_xino_read(sb, bindex, h_ino, &ino); ++ if (!err && ino) ++ inode = ilookup(sb, ino); ++ if (!inode) ++ goto out; ++ ++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { ++ pr_warn("wrong root branch\n"); ++ iput(inode); ++ inode = NULL; ++ goto out; ++ } ++ ++ ii_write_lock_child(inode); ++ ++out: ++ return inode; ++} ++ ++static void au_hn_bh(void *_args) ++{ ++ struct au_hnotify_args *a = _args; ++ struct super_block *sb; ++ aufs_bindex_t bindex, bbot, bfound; ++ unsigned char xino, try_iput; ++ int err; ++ struct inode *inode; ++ ino_t h_ino; ++ struct hn_job_args args; ++ struct dentry *dentry; ++ struct au_sbinfo *sbinfo; ++ ++ AuDebugOn(!_args); ++ AuDebugOn(!a->h_dir); ++ AuDebugOn(!a->dir); ++ AuDebugOn(!a->mask); ++ AuDbg("mask 0x%x, i%lu, hi%lu, hci%lu\n", ++ a->mask, a->dir->i_ino, a->h_dir->i_ino, ++ a->h_child_inode ? a->h_child_inode->i_ino : 0); ++ ++ inode = NULL; ++ dentry = NULL; ++ /* ++ * do not lock a->dir->i_mutex here ++ * because of d_revalidate() may cause a deadlock. ++ */ ++ sb = a->dir->i_sb; ++ AuDebugOn(!sb); ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!sbinfo); ++ si_write_lock(sb, AuLock_NOPLMW); ++ ++ if (au_opt_test(sbinfo->si_mntflags, DIRREN)) ++ switch (a->mask & FS_EVENTS_POSS_ON_CHILD) { ++ case FS_MOVED_FROM: ++ case FS_MOVED_TO: ++ AuWarn1("DIRREN with UDBA may not work correctly " ++ "for the direct rename(2)\n"); ++ } ++ ++ ii_read_lock_parent(a->dir); ++ bfound = -1; ++ bbot = au_ibbot(a->dir); ++ for (bindex = au_ibtop(a->dir); bindex <= bbot; bindex++) ++ if (au_h_iptr(a->dir, bindex) == a->h_dir) { ++ bfound = bindex; ++ break; ++ } ++ ii_read_unlock(a->dir); ++ if (unlikely(bfound < 0)) ++ goto out; ++ ++ xino = !!au_opt_test(au_mntflags(sb), XINO); ++ h_ino = 0; ++ if (a->h_child_inode) ++ h_ino = a->h_child_inode->i_ino; ++ ++ if (a->h_child_nlen ++ && (au_ftest_hnjob(a->flags[AuHn_CHILD], GEN) ++ || au_ftest_hnjob(a->flags[AuHn_CHILD], MNTPNT))) ++ dentry = lookup_wlock_by_name(a->h_child_name, a->h_child_nlen, ++ a->dir); ++ try_iput = 0; ++ if (dentry && d_really_is_positive(dentry)) ++ inode = d_inode(dentry); ++ if (xino && !inode && h_ino ++ && (au_ftest_hnjob(a->flags[AuHn_CHILD], XINO0) ++ || au_ftest_hnjob(a->flags[AuHn_CHILD], TRYXINO0) ++ || au_ftest_hnjob(a->flags[AuHn_CHILD], GEN))) { ++ inode = lookup_wlock_by_ino(sb, bfound, h_ino); ++ try_iput = 1; ++ } ++ ++ args.flags = a->flags[AuHn_CHILD]; ++ args.dentry = dentry; ++ args.inode = inode; ++ args.h_inode = a->h_child_inode; ++ args.dir = a->dir; ++ args.h_dir = a->h_dir; ++ args.h_name = a->h_child_name; ++ args.h_nlen = a->h_child_nlen; ++ err = hn_job(&args); ++ if (dentry) { ++ if (au_di(dentry)) ++ di_write_unlock(dentry); ++ dput(dentry); ++ } ++ if (inode && try_iput) { ++ ii_write_unlock(inode); ++ iput(inode); ++ } ++ ++ ii_write_lock_parent(a->dir); ++ args.flags = a->flags[AuHn_PARENT]; ++ args.dentry = NULL; ++ args.inode = a->dir; ++ args.h_inode = a->h_dir; ++ args.dir = NULL; ++ args.h_dir = NULL; ++ args.h_name = NULL; ++ args.h_nlen = 0; ++ err = hn_job(&args); ++ ii_write_unlock(a->dir); ++ ++out: ++ iput(a->h_child_inode); ++ iput(a->h_dir); ++ iput(a->dir); ++ si_write_unlock(sb); ++ au_nwt_done(&sbinfo->si_nowait); ++ au_kfree_rcu(a); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask, ++ const struct qstr *h_child_qstr, struct inode *h_child_inode) ++{ ++ int err, len; ++ unsigned int flags[AuHnLast], f; ++ unsigned char isdir, isroot, wh; ++ struct inode *dir; ++ struct au_hnotify_args *args; ++ char *p, *h_child_name; ++ ++ err = 0; ++ AuDebugOn(!hnotify || !hnotify->hn_aufs_inode); ++ dir = igrab(hnotify->hn_aufs_inode); ++ if (!dir) ++ goto out; ++ ++ isroot = (dir->i_ino == AUFS_ROOT_INO); ++ wh = 0; ++ h_child_name = (void *)h_child_qstr->name; ++ len = h_child_qstr->len; ++ if (h_child_name) { ++ if (len > AUFS_WH_PFX_LEN ++ && !memcmp(h_child_name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { ++ h_child_name += AUFS_WH_PFX_LEN; ++ len -= AUFS_WH_PFX_LEN; ++ wh = 1; ++ } ++ } ++ ++ isdir = 0; ++ if (h_child_inode) ++ isdir = !!S_ISDIR(h_child_inode->i_mode); ++ flags[AuHn_PARENT] = AuHnJob_ISDIR; ++ flags[AuHn_CHILD] = 0; ++ if (isdir) ++ flags[AuHn_CHILD] = AuHnJob_ISDIR; ++ au_fset_hnjob(flags[AuHn_PARENT], DIRENT); ++ au_fset_hnjob(flags[AuHn_CHILD], GEN); ++ switch (mask & ALL_FSNOTIFY_DIRENT_EVENTS) { ++ case FS_MOVED_FROM: ++ case FS_MOVED_TO: ++ au_fset_hnjob(flags[AuHn_CHILD], XINO0); ++ au_fset_hnjob(flags[AuHn_CHILD], MNTPNT); ++ fallthrough; ++ case FS_CREATE: ++ AuDebugOn(!h_child_name); ++ break; ++ ++ case FS_DELETE: ++ /* ++ * aufs never be able to get this child inode. ++ * revalidation should be in d_revalidate() ++ * by checking i_nlink, i_generation or d_unhashed(). ++ */ ++ AuDebugOn(!h_child_name); ++ au_fset_hnjob(flags[AuHn_CHILD], TRYXINO0); ++ au_fset_hnjob(flags[AuHn_CHILD], MNTPNT); ++ break; ++ ++ default: ++ AuDebugOn(1); ++ } ++ ++ if (wh) ++ h_child_inode = NULL; ++ ++ err = -ENOMEM; ++ /* iput() and kfree() will be called in au_hnotify() */ ++ args = kmalloc(sizeof(*args) + len + 1, GFP_NOFS); ++ if (unlikely(!args)) { ++ AuErr1("no memory\n"); ++ iput(dir); ++ goto out; ++ } ++ args->flags[AuHn_PARENT] = flags[AuHn_PARENT]; ++ args->flags[AuHn_CHILD] = flags[AuHn_CHILD]; ++ args->mask = mask; ++ args->dir = dir; ++ args->h_dir = igrab(h_dir); ++ if (h_child_inode) ++ h_child_inode = igrab(h_child_inode); /* can be NULL */ ++ args->h_child_inode = h_child_inode; ++ args->h_child_nlen = len; ++ if (len) { ++ p = (void *)args; ++ p += sizeof(*args); ++ memcpy(p, h_child_name, len); ++ p[len] = 0; ++ } ++ ++ /* NFS fires the event for silly-renamed one from kworker */ ++ f = 0; ++ if (!dir->i_nlink ++ || (au_test_nfs(h_dir->i_sb) && (mask & FS_DELETE))) ++ f = AuWkq_NEST; ++ err = au_wkq_nowait(au_hn_bh, args, dir->i_sb, f); ++ if (unlikely(err)) { ++ pr_err("wkq %d\n", err); ++ iput(args->h_child_inode); ++ iput(args->h_dir); ++ iput(args->dir); ++ au_kfree_rcu(args); ++ } ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_hnotify_reset_br(unsigned int udba, struct au_branch *br, int perm) ++{ ++ int err; ++ ++ AuDebugOn(!(udba & AuOptMask_UDBA)); ++ ++ err = 0; ++ if (au_hnotify_op.reset_br) ++ err = au_hnotify_op.reset_br(udba, br, perm); ++ ++ return err; ++} ++ ++int au_hnotify_init_br(struct au_branch *br, int perm) ++{ ++ int err; ++ ++ err = 0; ++ if (au_hnotify_op.init_br) ++ err = au_hnotify_op.init_br(br, perm); ++ ++ return err; ++} ++ ++void au_hnotify_fin_br(struct au_branch *br) ++{ ++ if (au_hnotify_op.fin_br) ++ au_hnotify_op.fin_br(br); ++} ++ ++static void au_hn_destroy_cache(void) ++{ ++ kmem_cache_destroy(au_cache[AuCache_HNOTIFY]); ++ au_cache[AuCache_HNOTIFY] = NULL; ++} ++ ++int __init au_hnotify_init(void) ++{ ++ int err; ++ ++ err = -ENOMEM; ++ au_cache[AuCache_HNOTIFY] = AuCache(au_hnotify); ++ if (au_cache[AuCache_HNOTIFY]) { ++ err = 0; ++ if (au_hnotify_op.init) ++ err = au_hnotify_op.init(); ++ if (unlikely(err)) ++ au_hn_destroy_cache(); ++ } ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_hnotify_fin(void) ++{ ++ if (au_hnotify_op.fin) ++ au_hnotify_op.fin(); ++ ++ /* cf. au_cache_fin() */ ++ if (au_cache[AuCache_HNOTIFY]) ++ au_hn_destroy_cache(); ++} +diff -Naur null/fs/aufs/iinfo.c linux-5.15.36/fs/aufs/iinfo.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/iinfo.c 2022-05-10 16:51:39.873744219 +0300 +@@ -0,0 +1,286 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * inode private data ++ */ ++ ++#include "aufs.h" ++ ++struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex) ++{ ++ struct inode *h_inode; ++ struct au_hinode *hinode; ++ ++ IiMustAnyLock(inode); ++ ++ hinode = au_hinode(au_ii(inode), bindex); ++ h_inode = hinode->hi_inode; ++ AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0); ++ return h_inode; ++} ++ ++/* todo: hard/soft set? */ ++void au_hiput(struct au_hinode *hinode) ++{ ++ au_hn_free(hinode); ++ dput(hinode->hi_whdentry); ++ iput(hinode->hi_inode); ++} ++ ++unsigned int au_hi_flags(struct inode *inode, int isdir) ++{ ++ unsigned int flags; ++ const unsigned int mnt_flags = au_mntflags(inode->i_sb); ++ ++ flags = 0; ++ if (au_opt_test(mnt_flags, XINO)) ++ au_fset_hi(flags, XINO); ++ if (isdir && au_opt_test(mnt_flags, UDBA_HNOTIFY)) ++ au_fset_hi(flags, HNOTIFY); ++ return flags; ++} ++ ++void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode, unsigned int flags) ++{ ++ struct au_hinode *hinode; ++ struct inode *hi; ++ struct au_iinfo *iinfo = au_ii(inode); ++ ++ IiMustWriteLock(inode); ++ ++ hinode = au_hinode(iinfo, bindex); ++ hi = hinode->hi_inode; ++ AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0); ++ ++ if (hi) ++ au_hiput(hinode); ++ hinode->hi_inode = h_inode; ++ if (h_inode) { ++ int err; ++ struct super_block *sb = inode->i_sb; ++ struct au_branch *br; ++ ++ AuDebugOn(inode->i_mode ++ && (h_inode->i_mode & S_IFMT) ++ != (inode->i_mode & S_IFMT)); ++ if (bindex == iinfo->ii_btop) ++ au_cpup_igen(inode, h_inode); ++ br = au_sbr(sb, bindex); ++ hinode->hi_id = br->br_id; ++ if (au_ftest_hi(flags, XINO)) { ++ err = au_xino_write(sb, bindex, h_inode->i_ino, ++ inode->i_ino); ++ if (unlikely(err)) ++ AuIOErr1("failed au_xino_write() %d\n", err); ++ } ++ ++ if (au_ftest_hi(flags, HNOTIFY) ++ && au_br_hnotifyable(br->br_perm)) { ++ err = au_hn_alloc(hinode, inode); ++ if (unlikely(err)) ++ AuIOErr1("au_hn_alloc() %d\n", err); ++ } ++ } ++} ++ ++void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_wh) ++{ ++ struct au_hinode *hinode; ++ ++ IiMustWriteLock(inode); ++ ++ hinode = au_hinode(au_ii(inode), bindex); ++ AuDebugOn(hinode->hi_whdentry); ++ hinode->hi_whdentry = h_wh; ++} ++ ++void au_update_iigen(struct inode *inode, int half) ++{ ++ struct au_iinfo *iinfo; ++ struct au_iigen *iigen; ++ unsigned int sigen; ++ ++ sigen = au_sigen(inode->i_sb); ++ iinfo = au_ii(inode); ++ iigen = &iinfo->ii_generation; ++ spin_lock(&iigen->ig_spin); ++ iigen->ig_generation = sigen; ++ if (half) ++ au_ig_fset(iigen->ig_flags, HALF_REFRESHED); ++ else ++ au_ig_fclr(iigen->ig_flags, HALF_REFRESHED); ++ spin_unlock(&iigen->ig_spin); ++} ++ ++/* it may be called at remount time, too */ ++void au_update_ibrange(struct inode *inode, int do_put_zero) ++{ ++ struct au_iinfo *iinfo; ++ aufs_bindex_t bindex, bbot; ++ ++ AuDebugOn(au_is_bad_inode(inode)); ++ IiMustWriteLock(inode); ++ ++ iinfo = au_ii(inode); ++ if (do_put_zero && iinfo->ii_btop >= 0) { ++ for (bindex = iinfo->ii_btop; bindex <= iinfo->ii_bbot; ++ bindex++) { ++ struct inode *h_i; ++ ++ h_i = au_hinode(iinfo, bindex)->hi_inode; ++ if (h_i ++ && !h_i->i_nlink ++ && !(h_i->i_state & I_LINKABLE)) ++ au_set_h_iptr(inode, bindex, NULL, 0); ++ } ++ } ++ ++ iinfo->ii_btop = -1; ++ iinfo->ii_bbot = -1; ++ bbot = au_sbbot(inode->i_sb); ++ for (bindex = 0; bindex <= bbot; bindex++) ++ if (au_hinode(iinfo, bindex)->hi_inode) { ++ iinfo->ii_btop = bindex; ++ break; ++ } ++ if (iinfo->ii_btop >= 0) ++ for (bindex = bbot; bindex >= iinfo->ii_btop; bindex--) ++ if (au_hinode(iinfo, bindex)->hi_inode) { ++ iinfo->ii_bbot = bindex; ++ break; ++ } ++ AuDebugOn(iinfo->ii_btop > iinfo->ii_bbot); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_icntnr_init_once(void *_c) ++{ ++ struct au_icntnr *c = _c; ++ struct au_iinfo *iinfo = &c->iinfo; ++ ++ spin_lock_init(&iinfo->ii_generation.ig_spin); ++ au_rw_init(&iinfo->ii_rwsem); ++ inode_init_once(&c->vfs_inode); ++} ++ ++void au_hinode_init(struct au_hinode *hinode) ++{ ++ hinode->hi_inode = NULL; ++ hinode->hi_id = -1; ++ au_hn_init(hinode); ++ hinode->hi_whdentry = NULL; ++} ++ ++int au_iinfo_init(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ struct super_block *sb; ++ struct au_hinode *hi; ++ int nbr, i; ++ ++ sb = inode->i_sb; ++ iinfo = &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); ++ nbr = au_sbbot(sb) + 1; ++ if (unlikely(nbr <= 0)) ++ nbr = 1; ++ hi = kmalloc_array(nbr, sizeof(*iinfo->ii_hinode), GFP_NOFS); ++ if (hi) { ++ au_lcnt_inc(&au_sbi(sb)->si_ninodes); ++ ++ iinfo->ii_hinode = hi; ++ for (i = 0; i < nbr; i++, hi++) ++ au_hinode_init(hi); ++ ++ iinfo->ii_generation.ig_generation = au_sigen(sb); ++ iinfo->ii_btop = -1; ++ iinfo->ii_bbot = -1; ++ iinfo->ii_vdir = NULL; ++ return 0; ++ } ++ return -ENOMEM; ++} ++ ++int au_hinode_realloc(struct au_iinfo *iinfo, int nbr, int may_shrink) ++{ ++ int err, i; ++ struct au_hinode *hip; ++ ++ AuRwMustWriteLock(&iinfo->ii_rwsem); ++ ++ err = -ENOMEM; ++ hip = au_krealloc(iinfo->ii_hinode, sizeof(*hip) * nbr, GFP_NOFS, ++ may_shrink); ++ if (hip) { ++ iinfo->ii_hinode = hip; ++ i = iinfo->ii_bbot + 1; ++ hip += i; ++ for (; i < nbr; i++, hip++) ++ au_hinode_init(hip); ++ err = 0; ++ } ++ ++ return err; ++} ++ ++void au_iinfo_fin(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ struct au_hinode *hi; ++ struct super_block *sb; ++ aufs_bindex_t bindex, bbot; ++ const unsigned char unlinked = !inode->i_nlink; ++ ++ AuDebugOn(au_is_bad_inode(inode)); ++ ++ sb = inode->i_sb; ++ au_lcnt_dec(&au_sbi(sb)->si_ninodes); ++ if (si_pid_test(sb)) ++ au_xino_delete_inode(inode, unlinked); ++ else { ++ /* ++ * it is safe to hide the dependency between sbinfo and ++ * sb->s_umount. ++ */ ++ lockdep_off(); ++ si_noflush_read_lock(sb); ++ au_xino_delete_inode(inode, unlinked); ++ si_read_unlock(sb); ++ lockdep_on(); ++ } ++ ++ iinfo = au_ii(inode); ++ if (iinfo->ii_vdir) ++ au_vdir_free(iinfo->ii_vdir); ++ ++ bindex = iinfo->ii_btop; ++ if (bindex >= 0) { ++ hi = au_hinode(iinfo, bindex); ++ bbot = iinfo->ii_bbot; ++ while (bindex++ <= bbot) { ++ if (hi->hi_inode) ++ au_hiput(hi); ++ hi++; ++ } ++ } ++ au_kfree_rcu(iinfo->ii_hinode); ++ AuRwDestroy(&iinfo->ii_rwsem); ++} +diff -Naur null/fs/aufs/inode.c linux-5.15.36/fs/aufs/inode.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/inode.c 2022-05-10 16:51:39.873744219 +0300 +@@ -0,0 +1,531 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * inode functions ++ */ ++ ++#include ++#include "aufs.h" ++ ++struct inode *au_igrab(struct inode *inode) ++{ ++ if (inode) { ++ AuDebugOn(!atomic_read(&inode->i_count)); ++ ihold(inode); ++ } ++ return inode; ++} ++ ++static void au_refresh_hinode_attr(struct inode *inode, int do_version) ++{ ++ au_cpup_attr_all(inode, /*force*/0); ++ au_update_iigen(inode, /*half*/1); ++ if (do_version) ++ inode_inc_iversion(inode); ++} ++ ++static int au_ii_refresh(struct inode *inode, int *update) ++{ ++ int err, e, nbr; ++ umode_t type; ++ aufs_bindex_t bindex, new_bindex; ++ struct super_block *sb; ++ struct au_iinfo *iinfo; ++ struct au_hinode *p, *q, tmp; ++ ++ AuDebugOn(au_is_bad_inode(inode)); ++ IiMustWriteLock(inode); ++ ++ *update = 0; ++ sb = inode->i_sb; ++ nbr = au_sbbot(sb) + 1; ++ type = inode->i_mode & S_IFMT; ++ iinfo = au_ii(inode); ++ err = au_hinode_realloc(iinfo, nbr, /*may_shrink*/0); ++ if (unlikely(err)) ++ goto out; ++ ++ AuDebugOn(iinfo->ii_btop < 0); ++ p = au_hinode(iinfo, iinfo->ii_btop); ++ for (bindex = iinfo->ii_btop; bindex <= iinfo->ii_bbot; ++ bindex++, p++) { ++ if (!p->hi_inode) ++ continue; ++ ++ AuDebugOn(type != (p->hi_inode->i_mode & S_IFMT)); ++ new_bindex = au_br_index(sb, p->hi_id); ++ if (new_bindex == bindex) ++ continue; ++ ++ if (new_bindex < 0) { ++ *update = 1; ++ au_hiput(p); ++ p->hi_inode = NULL; ++ continue; ++ } ++ ++ if (new_bindex < iinfo->ii_btop) ++ iinfo->ii_btop = new_bindex; ++ if (iinfo->ii_bbot < new_bindex) ++ iinfo->ii_bbot = new_bindex; ++ /* swap two lower inode, and loop again */ ++ q = au_hinode(iinfo, new_bindex); ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hi_inode) { ++ bindex--; ++ p--; ++ } ++ } ++ au_update_ibrange(inode, /*do_put_zero*/0); ++ au_hinode_realloc(iinfo, nbr, /*may_shrink*/1); /* harmless if err */ ++ e = au_dy_irefresh(inode); ++ if (unlikely(e && !err)) ++ err = e; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_refresh_iop(struct inode *inode, int force_getattr) ++{ ++ int type; ++ struct au_sbinfo *sbi = au_sbi(inode->i_sb); ++ const struct inode_operations *iop ++ = force_getattr ? aufs_iop : sbi->si_iop_array; ++ ++ if (inode->i_op == iop) ++ return; ++ ++ switch (inode->i_mode & S_IFMT) { ++ case S_IFDIR: ++ type = AuIop_DIR; ++ break; ++ case S_IFLNK: ++ type = AuIop_SYMLINK; ++ break; ++ default: ++ type = AuIop_OTHER; ++ break; ++ } ++ ++ inode->i_op = iop + type; ++ /* unnecessary smp_wmb() */ ++} ++ ++int au_refresh_hinode_self(struct inode *inode) ++{ ++ int err, update; ++ ++ err = au_ii_refresh(inode, &update); ++ if (!err) ++ au_refresh_hinode_attr(inode, update && S_ISDIR(inode->i_mode)); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_refresh_hinode(struct inode *inode, struct dentry *dentry) ++{ ++ int err, e, update; ++ unsigned int flags; ++ umode_t mode; ++ aufs_bindex_t bindex, bbot; ++ unsigned char isdir; ++ struct au_hinode *p; ++ struct au_iinfo *iinfo; ++ ++ err = au_ii_refresh(inode, &update); ++ if (unlikely(err)) ++ goto out; ++ ++ update = 0; ++ iinfo = au_ii(inode); ++ p = au_hinode(iinfo, iinfo->ii_btop); ++ mode = (inode->i_mode & S_IFMT); ++ isdir = S_ISDIR(mode); ++ flags = au_hi_flags(inode, isdir); ++ bbot = au_dbbot(dentry); ++ for (bindex = au_dbtop(dentry); bindex <= bbot; bindex++) { ++ struct inode *h_i, *h_inode; ++ struct dentry *h_d; ++ ++ h_d = au_h_dptr(dentry, bindex); ++ if (!h_d || d_is_negative(h_d)) ++ continue; ++ ++ h_inode = d_inode(h_d); ++ AuDebugOn(mode != (h_inode->i_mode & S_IFMT)); ++ if (iinfo->ii_btop <= bindex && bindex <= iinfo->ii_bbot) { ++ h_i = au_h_iptr(inode, bindex); ++ if (h_i) { ++ if (h_i == h_inode) ++ continue; ++ err = -EIO; ++ break; ++ } ++ } ++ if (bindex < iinfo->ii_btop) ++ iinfo->ii_btop = bindex; ++ if (iinfo->ii_bbot < bindex) ++ iinfo->ii_bbot = bindex; ++ au_set_h_iptr(inode, bindex, au_igrab(h_inode), flags); ++ update = 1; ++ } ++ au_update_ibrange(inode, /*do_put_zero*/0); ++ e = au_dy_irefresh(inode); ++ if (unlikely(e && !err)) ++ err = e; ++ if (!err) ++ au_refresh_hinode_attr(inode, update && isdir); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int set_inode(struct inode *inode, struct dentry *dentry) ++{ ++ int err; ++ unsigned int flags; ++ umode_t mode; ++ aufs_bindex_t bindex, btop, btail; ++ unsigned char isdir; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct au_iinfo *iinfo; ++ const struct inode_operations *iop; ++ ++ IiMustWriteLock(inode); ++ ++ err = 0; ++ isdir = 0; ++ iop = au_sbi(inode->i_sb)->si_iop_array; ++ btop = au_dbtop(dentry); ++ h_dentry = au_h_dptr(dentry, btop); ++ h_inode = d_inode(h_dentry); ++ mode = h_inode->i_mode; ++ switch (mode & S_IFMT) { ++ case S_IFREG: ++ btail = au_dbtail(dentry); ++ inode->i_op = iop + AuIop_OTHER; ++ inode->i_fop = &aufs_file_fop; ++ err = au_dy_iaop(inode, btop, h_inode); ++ if (unlikely(err)) ++ goto out; ++ break; ++ case S_IFDIR: ++ isdir = 1; ++ btail = au_dbtaildir(dentry); ++ inode->i_op = iop + AuIop_DIR; ++ inode->i_fop = &aufs_dir_fop; ++ break; ++ case S_IFLNK: ++ btail = au_dbtail(dentry); ++ inode->i_op = iop + AuIop_SYMLINK; ++ break; ++ case S_IFBLK: ++ case S_IFCHR: ++ case S_IFIFO: ++ case S_IFSOCK: ++ btail = au_dbtail(dentry); ++ inode->i_op = iop + AuIop_OTHER; ++ init_special_inode(inode, mode, h_inode->i_rdev); ++ break; ++ default: ++ AuIOErr("Unknown file type 0%o\n", mode); ++ err = -EIO; ++ goto out; ++ } ++ ++ /* do not set hnotify for whiteouted dirs (SHWH mode) */ ++ flags = au_hi_flags(inode, isdir); ++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH) ++ && au_ftest_hi(flags, HNOTIFY) ++ && dentry->d_name.len > AUFS_WH_PFX_LEN ++ && !memcmp(dentry->d_name.name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) ++ au_fclr_hi(flags, HNOTIFY); ++ iinfo = au_ii(inode); ++ iinfo->ii_btop = btop; ++ iinfo->ii_bbot = btail; ++ for (bindex = btop; bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry) ++ au_set_h_iptr(inode, bindex, ++ au_igrab(d_inode(h_dentry)), flags); ++ } ++ au_cpup_attr_all(inode, /*force*/1); ++ /* ++ * to force calling aufs_get_acl() every time, ++ * do not call cache_no_acl() for aufs inode. ++ */ ++ ++out: ++ return err; ++} ++ ++/* ++ * successful returns with iinfo write_locked ++ * minus: errno ++ * zero: success, matched ++ * plus: no error, but unmatched ++ */ ++static int reval_inode(struct inode *inode, struct dentry *dentry) ++{ ++ int err; ++ unsigned int gen, igflags; ++ aufs_bindex_t bindex, bbot; ++ struct inode *h_inode, *h_dinode; ++ struct dentry *h_dentry; ++ ++ /* ++ * before this function, if aufs got any iinfo lock, it must be only ++ * one, the parent dir. ++ * it can happen by UDBA and the obsoleted inode number. ++ */ ++ err = -EIO; ++ if (unlikely(inode->i_ino == parent_ino(dentry))) ++ goto out; ++ ++ err = 1; ++ ii_write_lock_new_child(inode); ++ h_dentry = au_h_dptr(dentry, au_dbtop(dentry)); ++ h_dinode = d_inode(h_dentry); ++ bbot = au_ibbot(inode); ++ for (bindex = au_ibtop(inode); bindex <= bbot; bindex++) { ++ h_inode = au_h_iptr(inode, bindex); ++ if (!h_inode || h_inode != h_dinode) ++ continue; ++ ++ err = 0; ++ gen = au_iigen(inode, &igflags); ++ if (gen == au_digen(dentry) ++ && !au_ig_ftest(igflags, HALF_REFRESHED)) ++ break; ++ ++ /* fully refresh inode using dentry */ ++ err = au_refresh_hinode(inode, dentry); ++ if (!err) ++ au_update_iigen(inode, /*half*/0); ++ break; ++ } ++ ++ if (unlikely(err)) ++ ii_write_unlock(inode); ++out: ++ return err; ++} ++ ++int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ unsigned int d_type, ino_t *ino) ++{ ++ int err, idx; ++ const int isnondir = d_type != DT_DIR; ++ ++ /* prevent hardlinked inode number from race condition */ ++ if (isnondir) { ++ err = au_xinondir_enter(sb, bindex, h_ino, &idx); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ err = au_xino_read(sb, bindex, h_ino, ino); ++ if (unlikely(err)) ++ goto out_xinondir; ++ ++ if (!*ino) { ++ err = -EIO; ++ *ino = au_xino_new_ino(sb); ++ if (unlikely(!*ino)) ++ goto out_xinondir; ++ err = au_xino_write(sb, bindex, h_ino, *ino); ++ if (unlikely(err)) ++ goto out_xinondir; ++ } ++ ++out_xinondir: ++ if (isnondir && idx >= 0) ++ au_xinondir_leave(sb, bindex, h_ino, idx); ++out: ++ return err; ++} ++ ++/* successful returns with iinfo write_locked */ ++/* todo: return with unlocked? */ ++struct inode *au_new_inode(struct dentry *dentry, int must_new) ++{ ++ struct inode *inode, *h_inode; ++ struct dentry *h_dentry; ++ struct super_block *sb; ++ ino_t h_ino, ino; ++ int err, idx, hlinked; ++ aufs_bindex_t btop; ++ ++ sb = dentry->d_sb; ++ btop = au_dbtop(dentry); ++ h_dentry = au_h_dptr(dentry, btop); ++ h_inode = d_inode(h_dentry); ++ h_ino = h_inode->i_ino; ++ hlinked = !d_is_dir(h_dentry) && h_inode->i_nlink > 1; ++ ++new_ino: ++ /* ++ * stop 'race'-ing between hardlinks under different ++ * parents. ++ */ ++ if (hlinked) { ++ err = au_xinondir_enter(sb, btop, h_ino, &idx); ++ inode = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ err = au_xino_read(sb, btop, h_ino, &ino); ++ inode = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_xinondir; ++ ++ if (!ino) { ++ ino = au_xino_new_ino(sb); ++ if (unlikely(!ino)) { ++ inode = ERR_PTR(-EIO); ++ goto out_xinondir; ++ } ++ } ++ ++ AuDbg("i%lu\n", (unsigned long)ino); ++ inode = au_iget_locked(sb, ino); ++ err = PTR_ERR(inode); ++ if (IS_ERR(inode)) ++ goto out_xinondir; ++ ++ AuDbg("%lx, new %d\n", inode->i_state, !!(inode->i_state & I_NEW)); ++ if (inode->i_state & I_NEW) { ++ ii_write_lock_new_child(inode); ++ err = set_inode(inode, dentry); ++ if (!err) { ++ unlock_new_inode(inode); ++ goto out_xinondir; /* success */ ++ } ++ ++ /* ++ * iget_failed() calls iput(), but we need to call ++ * ii_write_unlock() after iget_failed(). so dirty hack for ++ * i_count. ++ */ ++ atomic_inc(&inode->i_count); ++ iget_failed(inode); ++ ii_write_unlock(inode); ++ au_xino_write(sb, btop, h_ino, /*ino*/0); ++ /* ignore this error */ ++ goto out_iput; ++ } else if (!must_new && !IS_DEADDIR(inode) && inode->i_nlink) { ++ /* ++ * horrible race condition between lookup, readdir and copyup ++ * (or something). ++ */ ++ if (hlinked && idx >= 0) ++ au_xinondir_leave(sb, btop, h_ino, idx); ++ err = reval_inode(inode, dentry); ++ if (unlikely(err < 0)) { ++ hlinked = 0; ++ goto out_iput; ++ } ++ if (!err) ++ goto out; /* success */ ++ else if (hlinked && idx >= 0) { ++ err = au_xinondir_enter(sb, btop, h_ino, &idx); ++ if (unlikely(err)) { ++ iput(inode); ++ inode = ERR_PTR(err); ++ goto out; ++ } ++ } ++ } ++ ++ if (unlikely(au_test_fs_unique_ino(h_inode))) ++ AuWarn1("Warning: Un-notified UDBA or repeatedly renamed dir," ++ " b%d, %s, %pd, hi%lu, i%lu.\n", ++ btop, au_sbtype(h_dentry->d_sb), dentry, ++ (unsigned long)h_ino, (unsigned long)ino); ++ ino = 0; ++ err = au_xino_write(sb, btop, h_ino, /*ino*/0); ++ if (!err) { ++ iput(inode); ++ if (hlinked && idx >= 0) ++ au_xinondir_leave(sb, btop, h_ino, idx); ++ goto new_ino; ++ } ++ ++out_iput: ++ iput(inode); ++ inode = ERR_PTR(err); ++out_xinondir: ++ if (hlinked && idx >= 0) ++ au_xinondir_leave(sb, btop, h_ino, idx); ++out: ++ return inode; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_test_ro(struct super_block *sb, aufs_bindex_t bindex, ++ struct inode *inode) ++{ ++ int err; ++ struct inode *hi; ++ ++ err = au_br_rdonly(au_sbr(sb, bindex)); ++ ++ /* pseudo-link after flushed may happen out of bounds */ ++ if (!err ++ && inode ++ && au_ibtop(inode) <= bindex ++ && bindex <= au_ibbot(inode)) { ++ /* ++ * permission check is unnecessary since vfsub routine ++ * will be called later ++ */ ++ hi = au_h_iptr(inode, bindex); ++ if (hi) ++ err = IS_IMMUTABLE(hi) ? -EROFS : 0; ++ } ++ ++ return err; ++} ++ ++int au_test_h_perm(struct user_namespace *h_userns, struct inode *h_inode, ++ int mask) ++{ ++ if (uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) ++ return 0; ++ return inode_permission(h_userns, h_inode, mask); ++} ++ ++int au_test_h_perm_sio(struct user_namespace *h_userns, struct inode *h_inode, ++ int mask) ++{ ++ if (au_test_nfs(h_inode->i_sb) ++ && (mask & MAY_WRITE) ++ && S_ISDIR(h_inode->i_mode)) ++ mask |= MAY_READ; /* force permission check */ ++ return au_test_h_perm(h_userns, h_inode, mask); ++} +diff -Naur null/fs/aufs/inode.h linux-5.15.36/fs/aufs/inode.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/inode.h 2022-05-10 16:51:39.873744219 +0300 +@@ -0,0 +1,705 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * inode operations ++ */ ++ ++#ifndef __AUFS_INODE_H__ ++#define __AUFS_INODE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "rwsem.h" ++ ++struct vfsmount; ++ ++struct au_hnotify { ++#ifdef CONFIG_AUFS_HNOTIFY ++#ifdef CONFIG_AUFS_HFSNOTIFY ++ /* never use fsnotify_add_vfsmount_mark() */ ++ struct fsnotify_mark hn_mark; ++#endif ++ struct inode *hn_aufs_inode; /* no get/put */ ++ struct rcu_head rcu; ++#endif ++} ____cacheline_aligned_in_smp; ++ ++struct au_hinode { ++ struct inode *hi_inode; ++ aufs_bindex_t hi_id; ++#ifdef CONFIG_AUFS_HNOTIFY ++ struct au_hnotify *hi_notify; ++#endif ++ ++ /* reference to the copied-up whiteout with get/put */ ++ struct dentry *hi_whdentry; ++}; ++ ++/* ig_flags */ ++#define AuIG_HALF_REFRESHED 1 ++#define au_ig_ftest(flags, name) ((flags) & AuIG_##name) ++#define au_ig_fset(flags, name) \ ++ do { (flags) |= AuIG_##name; } while (0) ++#define au_ig_fclr(flags, name) \ ++ do { (flags) &= ~AuIG_##name; } while (0) ++ ++struct au_iigen { ++ spinlock_t ig_spin; ++ __u32 ig_generation, ig_flags; ++}; ++ ++struct au_vdir; ++struct au_iinfo { ++ struct au_iigen ii_generation; ++ struct super_block *ii_hsb1; /* no get/put */ ++ ++ struct au_rwsem ii_rwsem; ++ aufs_bindex_t ii_btop, ii_bbot; ++ __u32 ii_higen; ++ struct au_hinode *ii_hinode; ++ struct au_vdir *ii_vdir; ++}; ++ ++struct au_icntnr { ++ struct au_iinfo iinfo; ++ struct inode vfs_inode; ++ struct hlist_bl_node plink; ++ struct rcu_head rcu; ++} ____cacheline_aligned_in_smp; ++ ++/* au_pin flags */ ++#define AuPin_DI_LOCKED 1 ++#define AuPin_MNT_WRITE (1 << 1) ++#define au_ftest_pin(flags, name) ((flags) & AuPin_##name) ++#define au_fset_pin(flags, name) \ ++ do { (flags) |= AuPin_##name; } while (0) ++#define au_fclr_pin(flags, name) \ ++ do { (flags) &= ~AuPin_##name; } while (0) ++ ++struct au_pin { ++ /* input */ ++ struct dentry *dentry; ++ unsigned int udba; ++ unsigned char lsc_di, lsc_hi, flags; ++ aufs_bindex_t bindex; ++ ++ /* output */ ++ struct dentry *parent; ++ struct au_hinode *hdir; ++ struct vfsmount *h_mnt; ++ ++ /* temporary unlock/relock for copyup */ ++ struct dentry *h_dentry, *h_parent; ++ struct au_branch *br; ++ struct task_struct *task; ++}; ++ ++void au_pin_hdir_unlock(struct au_pin *p); ++int au_pin_hdir_lock(struct au_pin *p); ++int au_pin_hdir_relock(struct au_pin *p); ++void au_pin_hdir_acquire_nest(struct au_pin *p); ++void au_pin_hdir_release(struct au_pin *p); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_iinfo *au_ii(struct inode *inode) ++{ ++ BUG_ON(is_bad_inode(inode)); ++ return &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* inode.c */ ++struct inode *au_igrab(struct inode *inode); ++void au_refresh_iop(struct inode *inode, int force_getattr); ++int au_refresh_hinode_self(struct inode *inode); ++int au_refresh_hinode(struct inode *inode, struct dentry *dentry); ++int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ unsigned int d_type, ino_t *ino); ++struct inode *au_new_inode(struct dentry *dentry, int must_new); ++int au_test_ro(struct super_block *sb, aufs_bindex_t bindex, ++ struct inode *inode); ++int au_test_h_perm(struct user_namespace *h_userns, struct inode *h_inode, ++ int mask); ++int au_test_h_perm_sio(struct user_namespace *h_userns, struct inode *h_inode, ++ int mask); ++ ++static inline int au_wh_ino(struct super_block *sb, aufs_bindex_t bindex, ++ ino_t h_ino, unsigned int d_type, ino_t *ino) ++{ ++#ifdef CONFIG_AUFS_SHWH ++ return au_ino(sb, bindex, h_ino, d_type, ino); ++#else ++ return 0; ++#endif ++} ++ ++/* i_op.c */ ++enum { ++ AuIop_SYMLINK, ++ AuIop_DIR, ++ AuIop_OTHER, ++ AuIop_Last ++}; ++extern struct inode_operations aufs_iop[AuIop_Last], /* not const */ ++ aufs_iop_nogetattr[AuIop_Last]; ++ ++/* au_wr_dir flags */ ++#define AuWrDir_ADD_ENTRY 1 ++#define AuWrDir_ISDIR (1 << 1) ++#define AuWrDir_TMPFILE (1 << 2) ++#define au_ftest_wrdir(flags, name) ((flags) & AuWrDir_##name) ++#define au_fset_wrdir(flags, name) \ ++ do { (flags) |= AuWrDir_##name; } while (0) ++#define au_fclr_wrdir(flags, name) \ ++ do { (flags) &= ~AuWrDir_##name; } while (0) ++ ++struct au_wr_dir_args { ++ aufs_bindex_t force_btgt; ++ unsigned char flags; ++}; ++int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry, ++ struct au_wr_dir_args *args); ++ ++struct dentry *au_pinned_h_parent(struct au_pin *pin); ++void au_pin_init(struct au_pin *pin, struct dentry *dentry, ++ aufs_bindex_t bindex, int lsc_di, int lsc_hi, ++ unsigned int udba, unsigned char flags); ++int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int udba, unsigned char flags) __must_check; ++int au_do_pin(struct au_pin *pin) __must_check; ++void au_unpin(struct au_pin *pin); ++int au_reval_for_attr(struct dentry *dentry, unsigned int sigen); ++ ++#define AuIcpup_DID_CPUP 1 ++#define au_ftest_icpup(flags, name) ((flags) & AuIcpup_##name) ++#define au_fset_icpup(flags, name) \ ++ do { (flags) |= AuIcpup_##name; } while (0) ++#define au_fclr_icpup(flags, name) \ ++ do { (flags) &= ~AuIcpup_##name; } while (0) ++ ++struct au_icpup_args { ++ unsigned char flags; ++ unsigned char pin_flags; ++ aufs_bindex_t btgt; ++ unsigned int udba; ++ struct au_pin pin; ++ struct path h_path; ++ struct inode *h_inode; ++}; ++ ++int au_pin_and_icpup(struct dentry *dentry, struct iattr *ia, ++ struct au_icpup_args *a); ++ ++int au_h_path_getattr(struct dentry *dentry, struct inode *inode, int force, ++ struct path *h_path, int locked); ++ ++/* i_op_add.c */ ++int au_may_add(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, int isdir); ++int aufs_mknod(struct user_namespace *userns, struct inode *dir, ++ struct dentry *dentry, umode_t mode, dev_t dev); ++int aufs_symlink(struct user_namespace *userns, struct inode *dir, ++ struct dentry *dentry, const char *symname); ++int aufs_create(struct user_namespace *userns, struct inode *dir, ++ struct dentry *dentry, umode_t mode, bool want_excl); ++struct vfsub_aopen_args; ++int au_aopen_or_create(struct inode *dir, struct dentry *dentry, ++ struct vfsub_aopen_args *args); ++int aufs_tmpfile(struct user_namespace *userns, struct inode *dir, ++ struct dentry *dentry, umode_t mode); ++int aufs_link(struct dentry *src_dentry, struct inode *dir, ++ struct dentry *dentry); ++int aufs_mkdir(struct user_namespace *userns, struct inode *dir, ++ struct dentry *dentry, umode_t mode); ++ ++/* i_op_del.c */ ++int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup); ++int au_may_del(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, int isdir); ++int aufs_unlink(struct inode *dir, struct dentry *dentry); ++int aufs_rmdir(struct inode *dir, struct dentry *dentry); ++ ++/* i_op_ren.c */ ++int au_wbr(struct dentry *dentry, aufs_bindex_t btgt); ++int aufs_rename(struct user_namespace *userns, ++ struct inode *_src_dir, struct dentry *_src_dentry, ++ struct inode *_dst_dir, struct dentry *_dst_dentry, ++ unsigned int _flags); ++ ++/* iinfo.c */ ++struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex); ++void au_hiput(struct au_hinode *hinode); ++void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_wh); ++unsigned int au_hi_flags(struct inode *inode, int isdir); ++ ++/* hinode flags */ ++#define AuHi_XINO 1 ++#define AuHi_HNOTIFY (1 << 1) ++#define au_ftest_hi(flags, name) ((flags) & AuHi_##name) ++#define au_fset_hi(flags, name) \ ++ do { (flags) |= AuHi_##name; } while (0) ++#define au_fclr_hi(flags, name) \ ++ do { (flags) &= ~AuHi_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_HNOTIFY ++#undef AuHi_HNOTIFY ++#define AuHi_HNOTIFY 0 ++#endif ++ ++void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode, unsigned int flags); ++ ++void au_update_iigen(struct inode *inode, int half); ++void au_update_ibrange(struct inode *inode, int do_put_zero); ++ ++void au_icntnr_init_once(void *_c); ++void au_hinode_init(struct au_hinode *hinode); ++int au_iinfo_init(struct inode *inode); ++void au_iinfo_fin(struct inode *inode); ++int au_hinode_realloc(struct au_iinfo *iinfo, int nbr, int may_shrink); ++ ++#ifdef CONFIG_PROC_FS ++/* plink.c */ ++int au_plink_maint(struct super_block *sb, int flags); ++struct au_sbinfo; ++void au_plink_maint_leave(struct au_sbinfo *sbinfo); ++int au_plink_maint_enter(struct super_block *sb); ++#ifdef CONFIG_AUFS_DEBUG ++void au_plink_list(struct super_block *sb); ++#else ++AuStubVoid(au_plink_list, struct super_block *sb) ++#endif ++int au_plink_test(struct inode *inode); ++struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex); ++void au_plink_append(struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_dentry); ++void au_plink_put(struct super_block *sb, int verbose); ++void au_plink_clean(struct super_block *sb, int verbose); ++void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id); ++#else ++AuStubInt0(au_plink_maint, struct super_block *sb, int flags); ++AuStubVoid(au_plink_maint_leave, struct au_sbinfo *sbinfo); ++AuStubInt0(au_plink_maint_enter, struct super_block *sb); ++AuStubVoid(au_plink_list, struct super_block *sb); ++AuStubInt0(au_plink_test, struct inode *inode); ++AuStub(struct dentry *, au_plink_lkup, return NULL, ++ struct inode *inode, aufs_bindex_t bindex); ++AuStubVoid(au_plink_append, struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_dentry); ++AuStubVoid(au_plink_put, struct super_block *sb, int verbose); ++AuStubVoid(au_plink_clean, struct super_block *sb, int verbose); ++AuStubVoid(au_plink_half_refresh, struct super_block *sb, aufs_bindex_t br_id); ++#endif /* CONFIG_PROC_FS */ ++ ++#ifdef CONFIG_AUFS_XATTR ++/* xattr.c */ ++int au_cpup_xattr(struct path *h_dst, struct path *h_src, int ignore_flags, ++ unsigned int verbose); ++ssize_t aufs_listxattr(struct dentry *dentry, char *list, size_t size); ++void au_xattr_init(struct super_block *sb); ++#else ++AuStubInt0(au_cpup_xattr, struct path *h_dst, struct path *h_src, ++ int ignore_flags, unsigned int verbose); ++AuStubVoid(au_xattr_init, struct super_block *sb); ++#endif ++ ++#ifdef CONFIG_FS_POSIX_ACL ++struct posix_acl *aufs_get_acl(struct inode *inode, int type, bool rcu); ++int aufs_set_acl(struct user_namespace *userns, struct inode *inode, ++ struct posix_acl *acl, int type); ++#endif ++ ++#if IS_ENABLED(CONFIG_AUFS_XATTR) || IS_ENABLED(CONFIG_FS_POSIX_ACL) ++enum { ++ AU_XATTR_SET, ++ AU_ACL_SET ++}; ++ ++struct au_sxattr { ++ int type; ++ union { ++ struct { ++ const char *name; ++ const void *value; ++ size_t size; ++ int flags; ++ } set; ++ struct { ++ struct posix_acl *acl; ++ int type; ++ } acl_set; ++ } u; ++}; ++ssize_t au_sxattr(struct dentry *dentry, struct inode *inode, ++ struct au_sxattr *arg); ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock subclass for iinfo */ ++enum { ++ AuLsc_II_CHILD, /* child first */ ++ AuLsc_II_CHILD2, /* rename(2), link(2), and cpup at hnotify */ ++ AuLsc_II_CHILD3, /* copyup dirs */ ++ AuLsc_II_PARENT, /* see AuLsc_I_PARENT in vfsub.h */ ++ AuLsc_II_PARENT2, ++ AuLsc_II_PARENT3, /* copyup dirs */ ++ AuLsc_II_NEW_CHILD ++}; ++ ++/* ++ * ii_read_lock_child, ii_write_lock_child, ++ * ii_read_lock_child2, ii_write_lock_child2, ++ * ii_read_lock_child3, ii_write_lock_child3, ++ * ii_read_lock_parent, ii_write_lock_parent, ++ * ii_read_lock_parent2, ii_write_lock_parent2, ++ * ii_read_lock_parent3, ii_write_lock_parent3, ++ * ii_read_lock_new_child, ii_write_lock_new_child, ++ */ ++#define AuReadLockFunc(name, lsc) \ ++static inline void ii_read_lock_##name(struct inode *i) \ ++{ \ ++ au_rw_read_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); \ ++} ++ ++#define AuWriteLockFunc(name, lsc) \ ++static inline void ii_write_lock_##name(struct inode *i) \ ++{ \ ++ au_rw_write_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); \ ++} ++ ++#define AuRWLockFuncs(name, lsc) \ ++ AuReadLockFunc(name, lsc) \ ++ AuWriteLockFunc(name, lsc) ++ ++AuRWLockFuncs(child, CHILD); ++AuRWLockFuncs(child2, CHILD2); ++AuRWLockFuncs(child3, CHILD3); ++AuRWLockFuncs(parent, PARENT); ++AuRWLockFuncs(parent2, PARENT2); ++AuRWLockFuncs(parent3, PARENT3); ++AuRWLockFuncs(new_child, NEW_CHILD); ++ ++#undef AuReadLockFunc ++#undef AuWriteLockFunc ++#undef AuRWLockFuncs ++ ++#define ii_read_unlock(i) au_rw_read_unlock(&au_ii(i)->ii_rwsem) ++#define ii_write_unlock(i) au_rw_write_unlock(&au_ii(i)->ii_rwsem) ++#define ii_downgrade_lock(i) au_rw_dgrade_lock(&au_ii(i)->ii_rwsem) ++ ++#define IiMustNoWaiters(i) AuRwMustNoWaiters(&au_ii(i)->ii_rwsem) ++#define IiMustAnyLock(i) AuRwMustAnyLock(&au_ii(i)->ii_rwsem) ++#define IiMustWriteLock(i) AuRwMustWriteLock(&au_ii(i)->ii_rwsem) ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline void au_icntnr_init(struct au_icntnr *c) ++{ ++#ifdef CONFIG_AUFS_DEBUG ++ c->vfs_inode.i_mode = 0; ++#endif ++} ++ ++static inline unsigned int au_iigen(struct inode *inode, unsigned int *igflags) ++{ ++ unsigned int gen; ++ struct au_iinfo *iinfo; ++ struct au_iigen *iigen; ++ ++ iinfo = au_ii(inode); ++ iigen = &iinfo->ii_generation; ++ spin_lock(&iigen->ig_spin); ++ if (igflags) ++ *igflags = iigen->ig_flags; ++ gen = iigen->ig_generation; ++ spin_unlock(&iigen->ig_spin); ++ ++ return gen; ++} ++ ++/* tiny test for inode number */ ++/* tmpfs generation is too rough */ ++static inline int au_test_higen(struct inode *inode, struct inode *h_inode) ++{ ++ struct au_iinfo *iinfo; ++ ++ iinfo = au_ii(inode); ++ AuRwMustAnyLock(&iinfo->ii_rwsem); ++ return !(iinfo->ii_hsb1 == h_inode->i_sb ++ && iinfo->ii_higen == h_inode->i_generation); ++} ++ ++static inline void au_iigen_dec(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ struct au_iigen *iigen; ++ ++ iinfo = au_ii(inode); ++ iigen = &iinfo->ii_generation; ++ spin_lock(&iigen->ig_spin); ++ iigen->ig_generation--; ++ spin_unlock(&iigen->ig_spin); ++} ++ ++static inline int au_iigen_test(struct inode *inode, unsigned int sigen) ++{ ++ int err; ++ ++ err = 0; ++ if (unlikely(inode && au_iigen(inode, NULL) != sigen)) ++ err = -EIO; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_hinode *au_hinode(struct au_iinfo *iinfo, ++ aufs_bindex_t bindex) ++{ ++ return iinfo->ii_hinode + bindex; ++} ++ ++static inline int au_is_bad_inode(struct inode *inode) ++{ ++ return !!(is_bad_inode(inode) || !au_hinode(au_ii(inode), 0)); ++} ++ ++static inline aufs_bindex_t au_ii_br_id(struct inode *inode, ++ aufs_bindex_t bindex) ++{ ++ IiMustAnyLock(inode); ++ return au_hinode(au_ii(inode), bindex)->hi_id; ++} ++ ++static inline aufs_bindex_t au_ibtop(struct inode *inode) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_btop; ++} ++ ++static inline aufs_bindex_t au_ibbot(struct inode *inode) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_bbot; ++} ++ ++static inline struct au_vdir *au_ivdir(struct inode *inode) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_vdir; ++} ++ ++static inline struct dentry *au_hi_wh(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustAnyLock(inode); ++ return au_hinode(au_ii(inode), bindex)->hi_whdentry; ++} ++ ++static inline void au_set_ibtop(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustWriteLock(inode); ++ au_ii(inode)->ii_btop = bindex; ++} ++ ++static inline void au_set_ibbot(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustWriteLock(inode); ++ au_ii(inode)->ii_bbot = bindex; ++} ++ ++static inline void au_set_ivdir(struct inode *inode, struct au_vdir *vdir) ++{ ++ IiMustWriteLock(inode); ++ au_ii(inode)->ii_vdir = vdir; ++} ++ ++static inline struct au_hinode *au_hi(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustAnyLock(inode); ++ return au_hinode(au_ii(inode), bindex); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct dentry *au_pinned_parent(struct au_pin *pin) ++{ ++ if (pin) ++ return pin->parent; ++ return NULL; ++} ++ ++static inline struct inode *au_pinned_h_dir(struct au_pin *pin) ++{ ++ if (pin && pin->hdir) ++ return pin->hdir->hi_inode; ++ return NULL; ++} ++ ++static inline struct au_hinode *au_pinned_hdir(struct au_pin *pin) ++{ ++ if (pin) ++ return pin->hdir; ++ return NULL; ++} ++ ++static inline void au_pin_set_dentry(struct au_pin *pin, struct dentry *dentry) ++{ ++ if (pin) ++ pin->dentry = dentry; ++} ++ ++static inline void au_pin_set_parent_lflag(struct au_pin *pin, ++ unsigned char lflag) ++{ ++ if (pin) { ++ if (lflag) ++ au_fset_pin(pin->flags, DI_LOCKED); ++ else ++ au_fclr_pin(pin->flags, DI_LOCKED); ++ } ++} ++ ++#if 0 /* reserved */ ++static inline void au_pin_set_parent(struct au_pin *pin, struct dentry *parent) ++{ ++ if (pin) { ++ dput(pin->parent); ++ pin->parent = dget(parent); ++ } ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_branch; ++#ifdef CONFIG_AUFS_HNOTIFY ++struct au_hnotify_op { ++ void (*ctl)(struct au_hinode *hinode, int do_set); ++ int (*alloc)(struct au_hinode *hinode); ++ ++ /* ++ * if it returns true, the caller should free hinode->hi_notify, ++ * otherwise ->free() frees it. ++ */ ++ int (*free)(struct au_hinode *hinode, ++ struct au_hnotify *hn) __must_check; ++ ++ void (*fin)(void); ++ int (*init)(void); ++ ++ int (*reset_br)(unsigned int udba, struct au_branch *br, int perm); ++ void (*fin_br)(struct au_branch *br); ++ int (*init_br)(struct au_branch *br, int perm); ++}; ++ ++/* hnotify.c */ ++int au_hn_alloc(struct au_hinode *hinode, struct inode *inode); ++void au_hn_free(struct au_hinode *hinode); ++void au_hn_ctl(struct au_hinode *hinode, int do_set); ++void au_hn_reset(struct inode *inode, unsigned int flags); ++int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask, ++ const struct qstr *h_child_qstr, struct inode *h_child_inode); ++int au_hnotify_reset_br(unsigned int udba, struct au_branch *br, int perm); ++int au_hnotify_init_br(struct au_branch *br, int perm); ++void au_hnotify_fin_br(struct au_branch *br); ++int __init au_hnotify_init(void); ++void au_hnotify_fin(void); ++ ++/* hfsnotify.c */ ++extern const struct au_hnotify_op au_hnotify_op; ++ ++static inline ++void au_hn_init(struct au_hinode *hinode) ++{ ++ hinode->hi_notify = NULL; ++} ++ ++static inline struct au_hnotify *au_hn(struct au_hinode *hinode) ++{ ++ return hinode->hi_notify; ++} ++ ++#else ++AuStub(int, au_hn_alloc, return -EOPNOTSUPP, ++ struct au_hinode *hinode __maybe_unused, ++ struct inode *inode __maybe_unused) ++AuStub(struct au_hnotify *, au_hn, return NULL, struct au_hinode *hinode) ++AuStubVoid(au_hn_free, struct au_hinode *hinode __maybe_unused) ++AuStubVoid(au_hn_ctl, struct au_hinode *hinode __maybe_unused, ++ int do_set __maybe_unused) ++AuStubVoid(au_hn_reset, struct inode *inode __maybe_unused, ++ unsigned int flags __maybe_unused) ++AuStubInt0(au_hnotify_reset_br, unsigned int udba __maybe_unused, ++ struct au_branch *br __maybe_unused, ++ int perm __maybe_unused) ++AuStubInt0(au_hnotify_init_br, struct au_branch *br __maybe_unused, ++ int perm __maybe_unused) ++AuStubVoid(au_hnotify_fin_br, struct au_branch *br __maybe_unused) ++AuStubInt0(__init au_hnotify_init, void) ++AuStubVoid(au_hnotify_fin, void) ++AuStubVoid(au_hn_init, struct au_hinode *hinode __maybe_unused) ++#endif /* CONFIG_AUFS_HNOTIFY */ ++ ++static inline void au_hn_suspend(struct au_hinode *hdir) ++{ ++ au_hn_ctl(hdir, /*do_set*/0); ++} ++ ++static inline void au_hn_resume(struct au_hinode *hdir) ++{ ++ au_hn_ctl(hdir, /*do_set*/1); ++} ++ ++static inline void au_hn_inode_lock(struct au_hinode *hdir) ++{ ++ inode_lock(hdir->hi_inode); ++ au_hn_suspend(hdir); ++} ++ ++static inline void au_hn_inode_lock_nested(struct au_hinode *hdir, ++ unsigned int sc __maybe_unused) ++{ ++ inode_lock_nested(hdir->hi_inode, sc); ++ au_hn_suspend(hdir); ++} ++ ++#if 0 /* unused */ ++#include "vfsub.h" ++static inline void au_hn_inode_lock_shared_nested(struct au_hinode *hdir, ++ unsigned int sc) ++{ ++ inode_lock_shared_nested(hdir->hi_inode, sc); ++ au_hn_suspend(hdir); ++} ++#endif ++ ++static inline void au_hn_inode_unlock(struct au_hinode *hdir) ++{ ++ au_hn_resume(hdir); ++ inode_unlock(hdir->hi_inode); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_INODE_H__ */ +diff -Naur null/fs/aufs/ioctl.c linux-5.15.36/fs/aufs/ioctl.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/ioctl.c 2022-05-10 16:51:39.874744219 +0300 +@@ -0,0 +1,220 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * ioctl ++ * plink-management and readdir in userspace. ++ * assist the pathconf(3) wrapper library. ++ * move-down ++ * File-based Hierarchical Storage Management. ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++static int au_wbr_fd(struct path *path, struct aufs_wbr_fd __user *arg) ++{ ++ int err, fd; ++ aufs_bindex_t wbi, bindex, bbot; ++ struct file *h_file; ++ struct super_block *sb; ++ struct dentry *root; ++ struct au_branch *br; ++ struct aufs_wbr_fd wbrfd = { ++ .oflags = au_dir_roflags, ++ .brid = -1 ++ }; ++ const int valid = O_RDONLY | O_NONBLOCK | O_LARGEFILE | O_DIRECTORY ++ | O_NOATIME | O_CLOEXEC; ++ ++ AuDebugOn(wbrfd.oflags & ~valid); ++ ++ if (arg) { ++ err = copy_from_user(&wbrfd, arg, sizeof(wbrfd)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ goto out; ++ } ++ ++ err = -EINVAL; ++ AuDbg("wbrfd{0%o, %d}\n", wbrfd.oflags, wbrfd.brid); ++ wbrfd.oflags |= au_dir_roflags; ++ AuDbg("0%o\n", wbrfd.oflags); ++ if (unlikely(wbrfd.oflags & ~valid)) ++ goto out; ++ } ++ ++ fd = get_unused_fd_flags(0); ++ err = fd; ++ if (unlikely(fd < 0)) ++ goto out; ++ ++ h_file = ERR_PTR(-EINVAL); ++ wbi = 0; ++ br = NULL; ++ sb = path->dentry->d_sb; ++ root = sb->s_root; ++ aufs_read_lock(root, AuLock_IR); ++ bbot = au_sbbot(sb); ++ if (wbrfd.brid >= 0) { ++ wbi = au_br_index(sb, wbrfd.brid); ++ if (unlikely(wbi < 0 || wbi > bbot)) ++ goto out_unlock; ++ } ++ ++ h_file = ERR_PTR(-ENOENT); ++ br = au_sbr(sb, wbi); ++ if (!au_br_writable(br->br_perm)) { ++ if (arg) ++ goto out_unlock; ++ ++ bindex = wbi + 1; ++ wbi = -1; ++ for (; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_writable(br->br_perm)) { ++ wbi = bindex; ++ br = au_sbr(sb, wbi); ++ break; ++ } ++ } ++ } ++ AuDbg("wbi %d\n", wbi); ++ if (wbi >= 0) ++ h_file = au_h_open(root, wbi, wbrfd.oflags, NULL, ++ /*force_wr*/0); ++ ++out_unlock: ++ aufs_read_unlock(root, AuLock_IR); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out_fd; ++ ++ au_lcnt_dec(&br->br_nfiles); /* cf. au_h_open() */ ++ fd_install(fd, h_file); ++ err = fd; ++ goto out; /* success */ ++ ++out_fd: ++ put_unused_fd(fd); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ long err; ++ struct dentry *dentry; ++ ++ switch (cmd) { ++ case AUFS_CTL_RDU: ++ case AUFS_CTL_RDU_INO: ++ err = au_rdu_ioctl(file, cmd, arg); ++ break; ++ ++ case AUFS_CTL_WBR_FD: ++ err = au_wbr_fd(&file->f_path, (void __user *)arg); ++ break; ++ ++ case AUFS_CTL_IBUSY: ++ err = au_ibusy_ioctl(file, arg); ++ break; ++ ++ case AUFS_CTL_BRINFO: ++ err = au_brinfo_ioctl(file, arg); ++ break; ++ ++ case AUFS_CTL_FHSM_FD: ++ dentry = file->f_path.dentry; ++ if (IS_ROOT(dentry)) ++ err = au_fhsm_fd(dentry->d_sb, arg); ++ else ++ err = -ENOTTY; ++ break; ++ ++ default: ++ /* do not call the lower */ ++ AuDbg("0x%x\n", cmd); ++ err = -ENOTTY; ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ long err; ++ ++ switch (cmd) { ++ case AUFS_CTL_MVDOWN: ++ err = au_mvdown(file->f_path.dentry, (void __user *)arg); ++ break; ++ ++ case AUFS_CTL_WBR_FD: ++ err = au_wbr_fd(&file->f_path, (void __user *)arg); ++ break; ++ ++ default: ++ /* do not call the lower */ ++ AuDbg("0x%x\n", cmd); ++ err = -ENOTTY; ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++#ifdef CONFIG_COMPAT ++long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ long err; ++ ++ switch (cmd) { ++ case AUFS_CTL_RDU: ++ case AUFS_CTL_RDU_INO: ++ err = au_rdu_compat_ioctl(file, cmd, arg); ++ break; ++ ++ case AUFS_CTL_IBUSY: ++ err = au_ibusy_compat_ioctl(file, arg); ++ break; ++ ++ case AUFS_CTL_BRINFO: ++ err = au_brinfo_compat_ioctl(file, arg); ++ break; ++ ++ default: ++ err = aufs_ioctl_dir(file, cmd, arg); ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++long aufs_compat_ioctl_nondir(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ return aufs_ioctl_nondir(file, cmd, (unsigned long)compat_ptr(arg)); ++} ++#endif +diff -Naur null/fs/aufs/i_op_add.c linux-5.15.36/fs/aufs/i_op_add.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/i_op_add.c 2022-05-10 16:51:39.872744219 +0300 +@@ -0,0 +1,941 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * inode operations (add entry) ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* ++ * final procedure of adding a new entry, except link(2). ++ * remove whiteout, instantiate, copyup the parent dir's times and size ++ * and update version. ++ * if it failed, re-create the removed whiteout. ++ */ ++static int epilog(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct dentry *dentry) ++{ ++ int err, rerr; ++ aufs_bindex_t bwh; ++ struct path h_path; ++ struct super_block *sb; ++ struct inode *inode, *h_dir; ++ struct dentry *wh; ++ ++ bwh = -1; ++ sb = dir->i_sb; ++ if (wh_dentry) { ++ h_dir = d_inode(wh_dentry->d_parent); /* dir inode is locked */ ++ IMustLock(h_dir); ++ AuDebugOn(au_h_iptr(dir, bindex) != h_dir); ++ bwh = au_dbwh(dentry); ++ h_path.dentry = wh_dentry; ++ h_path.mnt = au_sbr_mnt(sb, bindex); ++ err = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path, ++ dentry); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ inode = au_new_inode(dentry, /*must_new*/1); ++ if (!IS_ERR(inode)) { ++ d_instantiate(dentry, inode); ++ dir = d_inode(dentry->d_parent); /* dir inode is locked */ ++ IMustLock(dir); ++ au_dir_ts(dir, bindex); ++ inode_inc_iversion(dir); ++ au_fhsm_wrote(sb, bindex, /*force*/0); ++ return 0; /* success */ ++ } ++ ++ err = PTR_ERR(inode); ++ if (!wh_dentry) ++ goto out; ++ ++ /* revert */ ++ /* dir inode is locked */ ++ wh = au_wh_create(dentry, bwh, wh_dentry->d_parent); ++ rerr = PTR_ERR(wh); ++ if (IS_ERR(wh)) { ++ AuIOErr("%pd reverting whiteout failed(%d, %d)\n", ++ dentry, err, rerr); ++ err = -EIO; ++ } else ++ dput(wh); ++ ++out: ++ return err; ++} ++ ++static int au_d_may_add(struct dentry *dentry) ++{ ++ int err; ++ ++ err = 0; ++ if (unlikely(d_unhashed(dentry))) ++ err = -ENOENT; ++ if (unlikely(d_really_is_positive(dentry))) ++ err = -EEXIST; ++ return err; ++} ++ ++/* ++ * simple tests for the adding inode operations. ++ * following the checks in vfs, plus the parent-child relationship. ++ */ ++int au_may_add(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, int isdir) ++{ ++ int err; ++ umode_t h_mode; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ ++ err = -ENAMETOOLONG; ++ if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) ++ goto out; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (d_really_is_negative(dentry)) { ++ err = -EEXIST; ++ if (unlikely(d_is_positive(h_dentry))) ++ goto out; ++ } else { ++ /* rename(2) case */ ++ err = -EIO; ++ if (unlikely(d_is_negative(h_dentry))) ++ goto out; ++ h_inode = d_inode(h_dentry); ++ if (unlikely(!h_inode->i_nlink)) ++ goto out; ++ ++ h_mode = h_inode->i_mode; ++ if (!isdir) { ++ err = -EISDIR; ++ if (unlikely(S_ISDIR(h_mode))) ++ goto out; ++ } else if (unlikely(!S_ISDIR(h_mode))) { ++ err = -ENOTDIR; ++ goto out; ++ } ++ } ++ ++ err = 0; ++ /* expected parent dir is locked */ ++ if (unlikely(h_parent != h_dentry->d_parent)) ++ err = -EIO; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * initial procedure of adding a new entry. ++ * prepare writable branch and the parent dir, lock it, ++ * and lookup whiteout for the new entry. ++ */ ++static struct dentry* ++lock_hdir_lkup_wh(struct dentry *dentry, struct au_dtime *dt, ++ struct dentry *src_dentry, struct au_pin *pin, ++ struct au_wr_dir_args *wr_dir_args) ++{ ++ struct dentry *wh_dentry, *h_parent; ++ struct super_block *sb; ++ struct au_branch *br; ++ int err; ++ unsigned int udba; ++ aufs_bindex_t bcpup; ++ ++ AuDbg("%pd\n", dentry); ++ ++ err = au_wr_dir(dentry, src_dentry, wr_dir_args); ++ bcpup = err; ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err < 0)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ udba = au_opt_udba(sb); ++ err = au_pin(pin, dentry, bcpup, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ h_parent = au_pinned_h_parent(pin); ++ if (udba != AuOpt_UDBA_NONE ++ && au_dbtop(dentry) == bcpup) ++ err = au_may_add(dentry, bcpup, h_parent, ++ au_ftest_wrdir(wr_dir_args->flags, ISDIR)); ++ else if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) ++ err = -ENAMETOOLONG; ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_unpin; ++ ++ br = au_sbr(sb, bcpup); ++ if (dt) { ++ struct path tmp = { ++ .dentry = h_parent, ++ .mnt = au_br_mnt(br) ++ }; ++ au_dtime_store(dt, au_pinned_parent(pin), &tmp); ++ } ++ ++ wh_dentry = NULL; ++ if (bcpup != au_dbwh(dentry)) ++ goto out; /* success */ ++ ++ /* ++ * ENAMETOOLONG here means that if we allowed create such name, then it ++ * would not be able to removed in the future. So we don't allow such ++ * name here and we don't handle ENAMETOOLONG differently here. ++ */ ++ wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, br); ++ ++out_unpin: ++ if (IS_ERR(wh_dentry)) ++ au_unpin(pin); ++out: ++ return wh_dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++enum { Mknod, Symlink, Creat }; ++struct simple_arg { ++ int type; ++ union { ++ struct { ++ umode_t mode; ++ bool want_excl; ++ bool try_aopen; ++ struct vfsub_aopen_args *aopen; ++ } c; ++ struct { ++ const char *symname; ++ } s; ++ struct { ++ umode_t mode; ++ dev_t dev; ++ } m; ++ } u; ++}; ++ ++static int add_simple(struct inode *dir, struct dentry *dentry, ++ struct simple_arg *arg) ++{ ++ int err, rerr; ++ aufs_bindex_t btop; ++ unsigned char created; ++ const unsigned char try_aopen ++ = (arg->type == Creat && arg->u.c.try_aopen); ++ struct vfsub_aopen_args *aopen = arg->u.c.aopen; ++ struct dentry *wh_dentry, *parent; ++ struct inode *h_dir; ++ struct super_block *sb; ++ struct au_branch *br; ++ /* to reduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct au_pin pin; ++ struct path h_path; ++ struct au_wr_dir_args wr_dir_args; ++ } *a; ++ ++ AuDbg("%pd\n", dentry); ++ IMustLock(dir); ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ a->wr_dir_args.force_btgt = -1; ++ a->wr_dir_args.flags = AuWrDir_ADD_ENTRY; ++ ++ parent = dentry->d_parent; /* dir inode is locked */ ++ if (!try_aopen) { ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_free; ++ } ++ err = au_d_may_add(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ if (!try_aopen) ++ di_write_lock_parent(parent); ++ wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL, ++ &a->pin, &a->wr_dir_args); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ btop = au_dbtop(dentry); ++ sb = dentry->d_sb; ++ br = au_sbr(sb, btop); ++ a->h_path.dentry = au_h_dptr(dentry, btop); ++ a->h_path.mnt = au_br_mnt(br); ++ h_dir = au_pinned_h_dir(&a->pin); ++ switch (arg->type) { ++ case Creat: ++ if (!try_aopen || !h_dir->i_op->atomic_open) { ++ err = vfsub_create(h_dir, &a->h_path, arg->u.c.mode, ++ arg->u.c.want_excl); ++ created = !err; ++ if (!err && try_aopen) ++ aopen->file->f_mode |= FMODE_CREATED; ++ } else { ++ aopen->br = br; ++ err = vfsub_atomic_open(h_dir, a->h_path.dentry, aopen); ++ AuDbg("err %d\n", err); ++ AuDbgFile(aopen->file); ++ created = err >= 0 ++ && !!(aopen->file->f_mode & FMODE_CREATED); ++ } ++ break; ++ case Symlink: ++ err = vfsub_symlink(h_dir, &a->h_path, arg->u.s.symname); ++ created = !err; ++ break; ++ case Mknod: ++ err = vfsub_mknod(h_dir, &a->h_path, arg->u.m.mode, ++ arg->u.m.dev); ++ created = !err; ++ break; ++ default: ++ BUG(); ++ } ++ if (unlikely(err < 0)) ++ goto out_unpin; ++ ++ err = epilog(dir, btop, wh_dentry, dentry); ++ if (!err) ++ goto out_unpin; /* success */ ++ ++ /* revert */ ++ if (created /* && d_is_positive(a->h_path.dentry) */) { ++ /* no delegation since it is just created */ ++ rerr = vfsub_unlink(h_dir, &a->h_path, /*delegated*/NULL, ++ /*force*/0); ++ if (rerr) { ++ AuIOErr("%pd revert failure(%d, %d)\n", ++ dentry, err, rerr); ++ err = -EIO; ++ } ++ au_dtime_revert(&a->dt); ++ } ++ if (try_aopen && h_dir->i_op->atomic_open ++ && (aopen->file->f_mode & FMODE_OPENED)) ++ /* aopen->file is still opened */ ++ au_lcnt_dec(&aopen->br->br_nfiles); ++ ++out_unpin: ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++out_parent: ++ if (!try_aopen) ++ di_write_unlock(parent); ++out_unlock: ++ if (unlikely(err)) { ++ au_update_dbtop(dentry); ++ d_drop(dentry); ++ } ++ if (!try_aopen) ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ au_kfree_rcu(a); ++out: ++ return err; ++} ++ ++int aufs_mknod(struct user_namespace *userns, struct inode *dir, ++ struct dentry *dentry, umode_t mode, dev_t dev) ++{ ++ struct simple_arg arg = { ++ .type = Mknod, ++ .u.m = { ++ .mode = mode, ++ .dev = dev ++ } ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int aufs_symlink(struct user_namespace *userns, struct inode *dir, ++ struct dentry *dentry, const char *symname) ++{ ++ struct simple_arg arg = { ++ .type = Symlink, ++ .u.s.symname = symname ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int aufs_create(struct user_namespace *userns, struct inode *dir, ++ struct dentry *dentry, umode_t mode, bool want_excl) ++{ ++ struct simple_arg arg = { ++ .type = Creat, ++ .u.c = { ++ .mode = mode, ++ .want_excl = want_excl ++ } ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int au_aopen_or_create(struct inode *dir, struct dentry *dentry, ++ struct vfsub_aopen_args *aopen_args) ++{ ++ struct simple_arg arg = { ++ .type = Creat, ++ .u.c = { ++ .mode = aopen_args->create_mode, ++ .want_excl = aopen_args->open_flag & O_EXCL, ++ .try_aopen = true, ++ .aopen = aopen_args ++ } ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int aufs_tmpfile(struct user_namespace *userns, struct inode *dir, ++ struct dentry *dentry, umode_t mode) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct super_block *sb; ++ struct dentry *parent, *h_parent, *h_dentry; ++ struct inode *h_dir, *inode; ++ struct vfsmount *h_mnt; ++ struct user_namespace *h_userns; ++ struct au_wr_dir_args wr_dir_args = { ++ .force_btgt = -1, ++ .flags = AuWrDir_TMPFILE ++ }; ++ ++ /* copy-up may happen */ ++ inode_lock(dir); ++ ++ sb = dir->i_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_di_init(dentry); ++ if (unlikely(err)) ++ goto out_si; ++ ++ err = -EBUSY; ++ parent = d_find_any_alias(dir); ++ AuDebugOn(!parent); ++ di_write_lock_parent(parent); ++ if (unlikely(d_inode(parent) != dir)) ++ goto out_parent; ++ ++ err = au_digen_test(parent, au_sigen(sb)); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ bindex = au_dbtop(parent); ++ au_set_dbtop(dentry, bindex); ++ au_set_dbbot(dentry, bindex); ++ err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args); ++ bindex = err; ++ if (unlikely(err < 0)) ++ goto out_parent; ++ ++ err = -EOPNOTSUPP; ++ h_dir = au_h_iptr(dir, bindex); ++ if (unlikely(!h_dir->i_op->tmpfile)) ++ goto out_parent; ++ ++ h_mnt = au_sbr_mnt(sb, bindex); ++ err = vfsub_mnt_want_write(h_mnt); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ h_userns = mnt_user_ns(h_mnt); ++ h_parent = au_h_dptr(parent, bindex); ++ h_dentry = vfs_tmpfile(h_userns, h_parent, mode, /*open_flag*/0); ++ if (IS_ERR(h_dentry)) { ++ err = PTR_ERR(h_dentry); ++ goto out_mnt; ++ } ++ ++ au_set_dbtop(dentry, bindex); ++ au_set_dbbot(dentry, bindex); ++ au_set_h_dptr(dentry, bindex, dget(h_dentry)); ++ inode = au_new_inode(dentry, /*must_new*/1); ++ if (IS_ERR(inode)) { ++ err = PTR_ERR(inode); ++ au_set_h_dptr(dentry, bindex, NULL); ++ au_set_dbtop(dentry, -1); ++ au_set_dbbot(dentry, -1); ++ } else { ++ if (!inode->i_nlink) ++ set_nlink(inode, 1); ++ d_tmpfile(dentry, inode); ++ au_di(dentry)->di_tmpfile = 1; ++ ++ /* update without i_mutex */ ++ if (au_ibtop(dir) == au_dbtop(dentry)) ++ au_cpup_attr_timesizes(dir); ++ } ++ dput(h_dentry); ++ ++out_mnt: ++ vfsub_mnt_drop_write(h_mnt); ++out_parent: ++ di_write_unlock(parent); ++ dput(parent); ++ di_write_unlock(dentry); ++ if (unlikely(err)) { ++ au_di_fin(dentry); ++ dentry->d_fsdata = NULL; ++ } ++out_si: ++ si_read_unlock(sb); ++out: ++ inode_unlock(dir); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_link_args { ++ aufs_bindex_t bdst, bsrc; ++ struct au_pin pin; ++ struct path h_path; ++ struct dentry *src_parent, *parent; ++}; ++ ++static int au_cpup_before_link(struct dentry *src_dentry, ++ struct au_link_args *a) ++{ ++ int err; ++ struct dentry *h_src_dentry; ++ struct au_cp_generic cpg = { ++ .dentry = src_dentry, ++ .bdst = a->bdst, ++ .bsrc = a->bsrc, ++ .len = -1, ++ .pin = &a->pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN /* | AuCpup_KEEPLINO */ ++ }; ++ ++ di_read_lock_parent(a->src_parent, AuLock_IR); ++ err = au_test_and_cpup_dirs(src_dentry, a->bdst); ++ if (unlikely(err)) ++ goto out; ++ ++ h_src_dentry = au_h_dptr(src_dentry, a->bsrc); ++ err = au_pin(&a->pin, src_dentry, a->bdst, ++ au_opt_udba(src_dentry->d_sb), ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&a->pin); ++ ++out: ++ di_read_unlock(a->src_parent, AuLock_IR); ++ return err; ++} ++ ++static int au_cpup_or_link(struct dentry *src_dentry, struct dentry *dentry, ++ struct au_link_args *a) ++{ ++ int err; ++ unsigned char plink; ++ aufs_bindex_t bbot; ++ struct dentry *h_src_dentry; ++ struct inode *h_inode, *inode, *delegated; ++ struct super_block *sb; ++ struct file *h_file; ++ ++ plink = 0; ++ h_inode = NULL; ++ sb = src_dentry->d_sb; ++ inode = d_inode(src_dentry); ++ if (au_ibtop(inode) <= a->bdst) ++ h_inode = au_h_iptr(inode, a->bdst); ++ if (!h_inode || !h_inode->i_nlink) { ++ /* copyup src_dentry as the name of dentry. */ ++ bbot = au_dbbot(dentry); ++ if (bbot < a->bsrc) ++ au_set_dbbot(dentry, a->bsrc); ++ au_set_h_dptr(dentry, a->bsrc, ++ dget(au_h_dptr(src_dentry, a->bsrc))); ++ dget(a->h_path.dentry); ++ au_set_h_dptr(dentry, a->bdst, NULL); ++ AuDbg("temporary d_inode...\n"); ++ spin_lock(&dentry->d_lock); ++ dentry->d_inode = d_inode(src_dentry); /* tmp */ ++ spin_unlock(&dentry->d_lock); ++ h_file = au_h_open_pre(dentry, a->bsrc, /*force_wr*/0); ++ if (IS_ERR(h_file)) ++ err = PTR_ERR(h_file); ++ else { ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = a->bdst, ++ .bsrc = -1, ++ .len = -1, ++ .pin = &a->pin, ++ .flags = AuCpup_KEEPLINO ++ }; ++ err = au_sio_cpup_simple(&cpg); ++ au_h_open_post(dentry, a->bsrc, h_file); ++ if (!err) { ++ dput(a->h_path.dentry); ++ a->h_path.dentry = au_h_dptr(dentry, a->bdst); ++ } else ++ au_set_h_dptr(dentry, a->bdst, ++ a->h_path.dentry); ++ } ++ spin_lock(&dentry->d_lock); ++ dentry->d_inode = NULL; /* restore */ ++ spin_unlock(&dentry->d_lock); ++ AuDbg("temporary d_inode...done\n"); ++ au_set_h_dptr(dentry, a->bsrc, NULL); ++ au_set_dbbot(dentry, bbot); ++ } else { ++ /* the inode of src_dentry already exists on a.bdst branch */ ++ h_src_dentry = d_find_alias(h_inode); ++ if (!h_src_dentry && au_plink_test(inode)) { ++ plink = 1; ++ h_src_dentry = au_plink_lkup(inode, a->bdst); ++ err = PTR_ERR(h_src_dentry); ++ if (IS_ERR(h_src_dentry)) ++ goto out; ++ ++ if (unlikely(d_is_negative(h_src_dentry))) { ++ dput(h_src_dentry); ++ h_src_dentry = NULL; ++ } ++ ++ } ++ if (h_src_dentry) { ++ delegated = NULL; ++ err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin), ++ &a->h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ dput(h_src_dentry); ++ } else { ++ AuIOErr("no dentry found for hi%lu on b%d\n", ++ h_inode->i_ino, a->bdst); ++ err = -EIO; ++ } ++ } ++ ++ if (!err && !plink) ++ au_plink_append(inode, a->bdst, a->h_path.dentry); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int aufs_link(struct dentry *src_dentry, struct inode *dir, ++ struct dentry *dentry) ++{ ++ int err, rerr; ++ struct au_dtime dt; ++ struct au_link_args *a; ++ struct dentry *wh_dentry, *h_src_dentry; ++ struct inode *inode, *delegated; ++ struct super_block *sb; ++ struct au_wr_dir_args wr_dir_args = { ++ /* .force_btgt = -1, */ ++ .flags = AuWrDir_ADD_ENTRY ++ }; ++ ++ IMustLock(dir); ++ inode = d_inode(src_dentry); ++ IMustLock(inode); ++ ++ err = -ENOMEM; ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ a->parent = dentry->d_parent; /* dir inode is locked */ ++ err = aufs_read_and_write_lock2(dentry, src_dentry, ++ AuLock_NOPLM | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_kfree; ++ err = au_d_linkable(src_dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ err = au_d_may_add(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ a->src_parent = dget_parent(src_dentry); ++ wr_dir_args.force_btgt = au_ibtop(inode); ++ ++ di_write_lock_parent(a->parent); ++ wr_dir_args.force_btgt = au_wbr(dentry, wr_dir_args.force_btgt); ++ wh_dentry = lock_hdir_lkup_wh(dentry, &dt, src_dentry, &a->pin, ++ &wr_dir_args); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ a->bdst = au_dbtop(dentry); ++ a->h_path.dentry = au_h_dptr(dentry, a->bdst); ++ a->h_path.mnt = au_sbr_mnt(sb, a->bdst); ++ a->bsrc = au_ibtop(inode); ++ h_src_dentry = au_h_d_alias(src_dentry, a->bsrc); ++ if (!h_src_dentry && au_di(src_dentry)->di_tmpfile) ++ h_src_dentry = dget(au_hi_wh(inode, a->bsrc)); ++ if (!h_src_dentry) { ++ a->bsrc = au_dbtop(src_dentry); ++ h_src_dentry = au_h_d_alias(src_dentry, a->bsrc); ++ AuDebugOn(!h_src_dentry); ++ } else if (IS_ERR(h_src_dentry)) { ++ err = PTR_ERR(h_src_dentry); ++ goto out_parent; ++ } ++ ++ /* ++ * aufs doesn't touch the credential so ++ * security_dentry_create_files_as() is unnecessary. ++ */ ++ if (au_opt_test(au_mntflags(sb), PLINK)) { ++ if (a->bdst < a->bsrc ++ /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */) ++ err = au_cpup_or_link(src_dentry, dentry, a); ++ else { ++ delegated = NULL; ++ err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin), ++ &a->h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ } ++ dput(h_src_dentry); ++ } else { ++ /* ++ * copyup src_dentry to the branch we process, ++ * and then link(2) to it. ++ */ ++ dput(h_src_dentry); ++ if (a->bdst < a->bsrc ++ /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */) { ++ au_unpin(&a->pin); ++ di_write_unlock(a->parent); ++ err = au_cpup_before_link(src_dentry, a); ++ di_write_lock_parent(a->parent); ++ if (!err) ++ err = au_pin(&a->pin, dentry, a->bdst, ++ au_opt_udba(sb), ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_wh; ++ } ++ if (!err) { ++ h_src_dentry = au_h_dptr(src_dentry, a->bdst); ++ err = -ENOENT; ++ if (h_src_dentry && d_is_positive(h_src_dentry)) { ++ delegated = NULL; ++ err = vfsub_link(h_src_dentry, ++ au_pinned_h_dir(&a->pin), ++ &a->h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry" ++ " for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ } ++ } ++ } ++ if (unlikely(err)) ++ goto out_unpin; ++ ++ if (wh_dentry) { ++ a->h_path.dentry = wh_dentry; ++ err = au_wh_unlink_dentry(au_pinned_h_dir(&a->pin), &a->h_path, ++ dentry); ++ if (unlikely(err)) ++ goto out_revert; ++ } ++ ++ au_dir_ts(dir, a->bdst); ++ inode_inc_iversion(dir); ++ inc_nlink(inode); ++ inode->i_ctime = dir->i_ctime; ++ d_instantiate(dentry, au_igrab(inode)); ++ if (d_unhashed(a->h_path.dentry)) ++ /* some filesystem calls d_drop() */ ++ d_drop(dentry); ++ /* some filesystems consume an inode even hardlink */ ++ au_fhsm_wrote(sb, a->bdst, /*force*/0); ++ goto out_unpin; /* success */ ++ ++out_revert: ++ /* no delegation since it is just created */ ++ rerr = vfsub_unlink(au_pinned_h_dir(&a->pin), &a->h_path, ++ /*delegated*/NULL, /*force*/0); ++ if (unlikely(rerr)) { ++ AuIOErr("%pd reverting failed(%d, %d)\n", dentry, err, rerr); ++ err = -EIO; ++ } ++ au_dtime_revert(&dt); ++out_unpin: ++ au_unpin(&a->pin); ++out_wh: ++ dput(wh_dentry); ++out_parent: ++ di_write_unlock(a->parent); ++ dput(a->src_parent); ++out_unlock: ++ if (unlikely(err)) { ++ au_update_dbtop(dentry); ++ d_drop(dentry); ++ } ++ aufs_read_and_write_unlock2(dentry, src_dentry); ++out_kfree: ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int aufs_mkdir(struct user_namespace *userns, struct inode *dir, ++ struct dentry *dentry, umode_t mode) ++{ ++ int err, rerr; ++ aufs_bindex_t bindex; ++ unsigned char diropq; ++ struct path h_path; ++ struct dentry *wh_dentry, *parent, *opq_dentry; ++ struct inode *h_inode; ++ struct super_block *sb; ++ struct { ++ struct au_pin pin; ++ struct au_dtime dt; ++ } *a; /* reduce the stack usage */ ++ struct au_wr_dir_args wr_dir_args = { ++ .force_btgt = -1, ++ .flags = AuWrDir_ADD_ENTRY | AuWrDir_ISDIR ++ }; ++ ++ IMustLock(dir); ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_free; ++ err = au_d_may_add(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ parent = dentry->d_parent; /* dir inode is locked */ ++ di_write_lock_parent(parent); ++ wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL, ++ &a->pin, &wr_dir_args); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ sb = dentry->d_sb; ++ bindex = au_dbtop(dentry); ++ h_path.dentry = au_h_dptr(dentry, bindex); ++ h_path.mnt = au_sbr_mnt(sb, bindex); ++ err = vfsub_mkdir(au_pinned_h_dir(&a->pin), &h_path, mode); ++ if (unlikely(err)) ++ goto out_unpin; ++ ++ /* make the dir opaque */ ++ diropq = 0; ++ h_inode = d_inode(h_path.dentry); ++ if (wh_dentry ++ || au_opt_test(au_mntflags(sb), ALWAYS_DIROPQ)) { ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ opq_dentry = au_diropq_create(dentry, bindex); ++ inode_unlock(h_inode); ++ err = PTR_ERR(opq_dentry); ++ if (IS_ERR(opq_dentry)) ++ goto out_dir; ++ dput(opq_dentry); ++ diropq = 1; ++ } ++ ++ err = epilog(dir, bindex, wh_dentry, dentry); ++ if (!err) { ++ inc_nlink(dir); ++ goto out_unpin; /* success */ ++ } ++ ++ /* revert */ ++ if (diropq) { ++ AuLabel(revert opq); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ rerr = au_diropq_remove(dentry, bindex); ++ inode_unlock(h_inode); ++ if (rerr) { ++ AuIOErr("%pd reverting diropq failed(%d, %d)\n", ++ dentry, err, rerr); ++ err = -EIO; ++ } ++ } ++ ++out_dir: ++ AuLabel(revert dir); ++ rerr = vfsub_rmdir(au_pinned_h_dir(&a->pin), &h_path); ++ if (rerr) { ++ AuIOErr("%pd reverting dir failed(%d, %d)\n", ++ dentry, err, rerr); ++ err = -EIO; ++ } ++ au_dtime_revert(&a->dt); ++out_unpin: ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++out_parent: ++ di_write_unlock(parent); ++out_unlock: ++ if (unlikely(err)) { ++ au_update_dbtop(dentry); ++ d_drop(dentry); ++ } ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ au_kfree_rcu(a); ++out: ++ return err; ++} +diff -Naur null/fs/aufs/i_op.c linux-5.15.36/fs/aufs/i_op.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/i_op.c 2022-05-10 16:51:39.872744219 +0300 +@@ -0,0 +1,1512 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * inode operations (except add/del/rename) ++ */ ++ ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++static int h_permission(struct inode *h_inode, int mask, ++ struct path *h_path, int brperm) ++{ ++ int err; ++ const unsigned char write_mask = !!(mask & (MAY_WRITE | MAY_APPEND)); ++ struct user_namespace *h_userns; ++ ++ err = -EPERM; ++ if (write_mask && IS_IMMUTABLE(h_inode)) ++ goto out; ++ ++ err = -EACCES; ++ if (((mask & MAY_EXEC) ++ && S_ISREG(h_inode->i_mode) ++ && (path_noexec(h_path) ++ || !(h_inode->i_mode & 0111)))) ++ goto out; ++ ++ /* ++ * - skip the lower fs test in the case of write to ro branch. ++ * - nfs dir permission write check is optimized, but a policy for ++ * link/rename requires a real check. ++ * - nfs always sets SB_POSIXACL regardless its mount option 'noacl.' ++ * in this case, generic_permission() returns -EOPNOTSUPP. ++ */ ++ h_userns = mnt_user_ns(h_path->mnt); ++ if ((write_mask && !au_br_writable(brperm)) ++ || (au_test_nfs(h_inode->i_sb) && S_ISDIR(h_inode->i_mode) ++ && write_mask && !(mask & MAY_READ)) ++ || !h_inode->i_op->permission) { ++ /* AuLabel(generic_permission); */ ++ /* AuDbg("get_acl %ps\n", h_inode->i_op->get_acl); */ ++ err = generic_permission(h_userns, h_inode, mask); ++ if (err == -EOPNOTSUPP && au_test_nfs_noacl(h_inode)) ++ err = h_inode->i_op->permission(h_userns, h_inode, ++ mask); ++ AuTraceErr(err); ++ } else { ++ /* AuLabel(h_inode->permission); */ ++ err = h_inode->i_op->permission(h_userns, h_inode, mask); ++ AuTraceErr(err); ++ } ++ ++ if (!err) ++ err = devcgroup_inode_permission(h_inode, mask); ++ if (!err) ++ err = security_inode_permission(h_inode, mask); ++ ++out: ++ return err; ++} ++ ++static int aufs_permission(struct user_namespace *userns, struct inode *inode, ++ int mask) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ const unsigned char isdir = !!S_ISDIR(inode->i_mode), ++ write_mask = !!(mask & (MAY_WRITE | MAY_APPEND)); ++ struct inode *h_inode; ++ struct super_block *sb; ++ struct au_branch *br; ++ ++ /* todo: support rcu-walk? */ ++ if (mask & MAY_NOT_BLOCK) ++ return -ECHILD; ++ ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ ii_read_lock_child(inode); ++#if 0 /* reserved for future use */ ++ /* ++ * This test may be rather 'too much' since the test is essentially done ++ * in the aufs_lookup(). Theoretically it is possible that the inode ++ * generation doesn't match to the superblock's here. But it isn't a ++ * big deal I suppose. ++ */ ++ err = au_iigen_test(inode, au_sigen(sb)); ++ if (unlikely(err)) ++ goto out; ++#endif ++ ++ if (!isdir ++ || write_mask ++ || au_opt_test(au_mntflags(sb), DIRPERM1)) { ++ err = au_busy_or_stale(); ++ h_inode = au_h_iptr(inode, au_ibtop(inode)); ++ if (unlikely(!h_inode ++ || (h_inode->i_mode & S_IFMT) ++ != (inode->i_mode & S_IFMT))) ++ goto out; ++ ++ err = 0; ++ bindex = au_ibtop(inode); ++ br = au_sbr(sb, bindex); ++ err = h_permission(h_inode, mask, &br->br_path, br->br_perm); ++ if (write_mask ++ && !err ++ && !special_file(h_inode->i_mode)) { ++ /* test whether the upper writable branch exists */ ++ err = -EROFS; ++ for (; bindex >= 0; bindex--) ++ if (!au_br_rdonly(au_sbr(sb, bindex))) { ++ err = 0; ++ break; ++ } ++ } ++ goto out; ++ } ++ ++ /* non-write to dir */ ++ err = 0; ++ bbot = au_ibbot(inode); ++ for (bindex = au_ibtop(inode); !err && bindex <= bbot; bindex++) { ++ h_inode = au_h_iptr(inode, bindex); ++ if (h_inode) { ++ err = au_busy_or_stale(); ++ if (unlikely(!S_ISDIR(h_inode->i_mode))) ++ break; ++ ++ br = au_sbr(sb, bindex); ++ err = h_permission(h_inode, mask, &br->br_path, ++ br->br_perm); ++ } ++ } ++ ++out: ++ ii_read_unlock(inode); ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry *aufs_lookup(struct inode *dir, struct dentry *dentry, ++ unsigned int flags) ++{ ++ struct dentry *ret, *parent; ++ struct inode *inode; ++ struct super_block *sb; ++ int err, npositive; ++ ++ IMustLock(dir); ++ ++ /* todo: support rcu-walk? */ ++ ret = ERR_PTR(-ECHILD); ++ if (flags & LOOKUP_RCU) ++ goto out; ++ ++ ret = ERR_PTR(-ENAMETOOLONG); ++ if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) ++ goto out; ++ ++ sb = dir->i_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ ret = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_di_init(dentry); ++ ret = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_si; ++ ++ inode = NULL; ++ npositive = 0; /* suppress a warning */ ++ parent = dentry->d_parent; /* dir inode is locked */ ++ di_read_lock_parent(parent, AuLock_IR); ++ err = au_alive_dir(parent); ++ if (!err) ++ err = au_digen_test(parent, au_sigen(sb)); ++ if (!err) { ++ /* regardless LOOKUP_CREATE, always ALLOW_NEG */ ++ npositive = au_lkup_dentry(dentry, au_dbtop(parent), ++ AuLkup_ALLOW_NEG); ++ err = npositive; ++ } ++ di_read_unlock(parent, AuLock_IR); ++ ret = ERR_PTR(err); ++ if (unlikely(err < 0)) ++ goto out_unlock; ++ ++ if (npositive) { ++ inode = au_new_inode(dentry, /*must_new*/0); ++ if (IS_ERR(inode)) { ++ ret = (void *)inode; ++ inode = NULL; ++ goto out_unlock; ++ } ++ } ++ ++ if (inode) ++ atomic_inc(&inode->i_count); ++ ret = d_splice_alias(inode, dentry); ++#if 0 /* reserved for future use */ ++ if (unlikely(d_need_lookup(dentry))) { ++ spin_lock(&dentry->d_lock); ++ dentry->d_flags &= ~DCACHE_NEED_LOOKUP; ++ spin_unlock(&dentry->d_lock); ++ } else ++#endif ++ if (inode) { ++ if (!IS_ERR(ret)) { ++ iput(inode); ++ if (ret && ret != dentry) ++ ii_write_unlock(inode); ++ } else { ++ ii_write_unlock(inode); ++ iput(inode); ++ inode = NULL; ++ } ++ } ++ ++out_unlock: ++ di_write_unlock(dentry); ++out_si: ++ si_read_unlock(sb); ++out: ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * very dirty and complicated aufs ->atomic_open(). ++ * aufs_atomic_open() ++ * + au_aopen_or_create() ++ * + add_simple() ++ * + vfsub_atomic_open() ++ * + branch fs ->atomic_open() ++ * may call the actual 'open' for h_file ++ * + inc br_nfiles only if opened ++ * + au_aopen_no_open() or au_aopen_do_open() ++ * ++ * au_aopen_do_open() ++ * + finish_open() ++ * + au_do_aopen() ++ * + au_do_open() the body of all 'open' ++ * + au_do_open_nondir() ++ * set the passed h_file ++ * ++ * au_aopen_no_open() ++ * + finish_no_open() ++ */ ++ ++struct aopen_node { ++ struct hlist_bl_node hblist; ++ struct file *file, *h_file; ++}; ++ ++static int au_do_aopen(struct inode *inode, struct file *file) ++{ ++ struct hlist_bl_head *aopen; ++ struct hlist_bl_node *pos; ++ struct aopen_node *node; ++ struct au_do_open_args args = { ++ .aopen = 1, ++ .open = au_do_open_nondir ++ }; ++ ++ aopen = &au_sbi(inode->i_sb)->si_aopen; ++ hlist_bl_lock(aopen); ++ hlist_bl_for_each_entry(node, pos, aopen, hblist) ++ if (node->file == file) { ++ args.h_file = node->h_file; ++ break; ++ } ++ hlist_bl_unlock(aopen); ++ /* AuDebugOn(!args.h_file); */ ++ ++ return au_do_open(file, &args); ++} ++ ++static int au_aopen_do_open(struct file *file, struct dentry *dentry, ++ struct aopen_node *aopen_node) ++{ ++ int err; ++ struct hlist_bl_head *aopen; ++ ++ AuLabel(here); ++ aopen = &au_sbi(dentry->d_sb)->si_aopen; ++ au_hbl_add(&aopen_node->hblist, aopen); ++ err = finish_open(file, dentry, au_do_aopen); ++ au_hbl_del(&aopen_node->hblist, aopen); ++ /* AuDbgFile(file); */ ++ AuDbg("%pd%s%s\n", dentry, ++ (file->f_mode & FMODE_CREATED) ? " created" : "", ++ (file->f_mode & FMODE_OPENED) ? " opened" : ""); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_aopen_no_open(struct file *file, struct dentry *dentry) ++{ ++ int err; ++ ++ AuLabel(here); ++ dget(dentry); ++ err = finish_no_open(file, dentry); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int aufs_atomic_open(struct inode *dir, struct dentry *dentry, ++ struct file *file, unsigned int open_flag, ++ umode_t create_mode) ++{ ++ int err, did_open; ++ unsigned int lkup_flags; ++ aufs_bindex_t bindex; ++ struct super_block *sb; ++ struct dentry *parent, *d; ++ struct vfsub_aopen_args args = { ++ .open_flag = open_flag, ++ .create_mode = create_mode ++ }; ++ struct aopen_node aopen_node = { ++ .file = file ++ }; ++ ++ IMustLock(dir); ++ AuDbg("open_flag 0%o\n", open_flag); ++ AuDbgDentry(dentry); ++ ++ err = 0; ++ if (!au_di(dentry)) { ++ lkup_flags = LOOKUP_OPEN; ++ if (open_flag & O_CREAT) ++ lkup_flags |= LOOKUP_CREATE; ++ d = aufs_lookup(dir, dentry, lkup_flags); ++ if (IS_ERR(d)) { ++ err = PTR_ERR(d); ++ AuTraceErr(err); ++ goto out; ++ } else if (d) { ++ /* ++ * obsoleted dentry found. ++ * another error will be returned later. ++ */ ++ d_drop(d); ++ AuDbgDentry(d); ++ dput(d); ++ } ++ AuDbgDentry(dentry); ++ } ++ ++ if (d_is_positive(dentry) ++ || d_unhashed(dentry) ++ || d_unlinked(dentry) ++ || !(open_flag & O_CREAT)) { ++ err = au_aopen_no_open(file, dentry); ++ goto out; /* success */ ++ } ++ ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_GEN); ++ if (unlikely(err)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ parent = dentry->d_parent; /* dir is locked */ ++ di_write_lock_parent(parent); ++ err = au_lkup_dentry(dentry, /*btop*/0, AuLkup_ALLOW_NEG); ++ if (unlikely(err < 0)) ++ goto out_parent; ++ ++ AuDbgDentry(dentry); ++ if (d_is_positive(dentry)) { ++ err = au_aopen_no_open(file, dentry); ++ goto out_parent; /* success */ ++ } ++ ++ args.file = alloc_empty_file(file->f_flags, current_cred()); ++ err = PTR_ERR(args.file); ++ if (IS_ERR(args.file)) ++ goto out_parent; ++ ++ bindex = au_dbtop(dentry); ++ err = au_aopen_or_create(dir, dentry, &args); ++ AuTraceErr(err); ++ AuDbgFile(args.file); ++ file->f_mode = args.file->f_mode & ~FMODE_OPENED; ++ did_open = !!(args.file->f_mode & FMODE_OPENED); ++ if (!did_open) { ++ fput(args.file); ++ args.file = NULL; ++ } ++ di_write_unlock(parent); ++ di_write_unlock(dentry); ++ if (unlikely(err < 0)) { ++ if (args.file) ++ fput(args.file); ++ goto out_sb; ++ } ++ ++ if (!did_open) ++ err = au_aopen_no_open(file, dentry); ++ else { ++ aopen_node.h_file = args.file; ++ err = au_aopen_do_open(file, dentry, &aopen_node); ++ } ++ if (unlikely(err < 0)) { ++ if (args.file) ++ fput(args.file); ++ if (did_open) ++ au_lcnt_dec(&args.br->br_nfiles); ++ } ++ goto out_sb; /* success */ ++ ++out_parent: ++ di_write_unlock(parent); ++ di_write_unlock(dentry); ++out_sb: ++ si_read_unlock(sb); ++out: ++ AuTraceErr(err); ++ AuDbgFile(file); ++ return err; ++} ++ ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_wr_dir_cpup(struct dentry *dentry, struct dentry *parent, ++ const unsigned char add_entry, aufs_bindex_t bcpup, ++ aufs_bindex_t btop) ++{ ++ int err; ++ struct dentry *h_parent; ++ struct inode *h_dir; ++ ++ if (add_entry) ++ IMustLock(d_inode(parent)); ++ else ++ di_write_lock_parent(parent); ++ ++ err = 0; ++ if (!au_h_dptr(parent, bcpup)) { ++ if (btop > bcpup) ++ err = au_cpup_dirs(dentry, bcpup); ++ else if (btop < bcpup) ++ err = au_cpdown_dirs(dentry, bcpup); ++ else ++ BUG(); ++ } ++ if (!err && add_entry && !au_ftest_wrdir(add_entry, TMPFILE)) { ++ h_parent = au_h_dptr(parent, bcpup); ++ h_dir = d_inode(h_parent); ++ inode_lock_shared_nested(h_dir, AuLsc_I_PARENT); ++ err = au_lkup_neg(dentry, bcpup, /*wh*/0); ++ /* todo: no unlock here */ ++ inode_unlock_shared(h_dir); ++ ++ AuDbg("bcpup %d\n", bcpup); ++ if (!err) { ++ if (d_really_is_negative(dentry)) ++ au_set_h_dptr(dentry, btop, NULL); ++ au_update_dbrange(dentry, /*do_put_zero*/0); ++ } ++ } ++ ++ if (!add_entry) ++ di_write_unlock(parent); ++ if (!err) ++ err = bcpup; /* success */ ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * decide the branch and the parent dir where we will create a new entry. ++ * returns new bindex or an error. ++ * copyup the parent dir if needed. ++ */ ++int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry, ++ struct au_wr_dir_args *args) ++{ ++ int err; ++ unsigned int flags; ++ aufs_bindex_t bcpup, btop, src_btop; ++ const unsigned char add_entry ++ = au_ftest_wrdir(args->flags, ADD_ENTRY) ++ | au_ftest_wrdir(args->flags, TMPFILE); ++ struct super_block *sb; ++ struct dentry *parent; ++ struct au_sbinfo *sbinfo; ++ ++ sb = dentry->d_sb; ++ sbinfo = au_sbi(sb); ++ parent = dget_parent(dentry); ++ btop = au_dbtop(dentry); ++ bcpup = btop; ++ if (args->force_btgt < 0) { ++ if (src_dentry) { ++ src_btop = au_dbtop(src_dentry); ++ if (src_btop < btop) ++ bcpup = src_btop; ++ } else if (add_entry) { ++ flags = 0; ++ if (au_ftest_wrdir(args->flags, ISDIR)) ++ au_fset_wbr(flags, DIR); ++ err = AuWbrCreate(sbinfo, dentry, flags); ++ bcpup = err; ++ } ++ ++ if (bcpup < 0 || au_test_ro(sb, bcpup, d_inode(dentry))) { ++ if (add_entry) ++ err = AuWbrCopyup(sbinfo, dentry); ++ else { ++ if (!IS_ROOT(dentry)) { ++ di_read_lock_parent(parent, !AuLock_IR); ++ err = AuWbrCopyup(sbinfo, dentry); ++ di_read_unlock(parent, !AuLock_IR); ++ } else ++ err = AuWbrCopyup(sbinfo, dentry); ++ } ++ bcpup = err; ++ if (unlikely(err < 0)) ++ goto out; ++ } ++ } else { ++ bcpup = args->force_btgt; ++ AuDebugOn(au_test_ro(sb, bcpup, d_inode(dentry))); ++ } ++ ++ AuDbg("btop %d, bcpup %d\n", btop, bcpup); ++ err = bcpup; ++ if (bcpup == btop) ++ goto out; /* success */ ++ ++ /* copyup the new parent into the branch we process */ ++ err = au_wr_dir_cpup(dentry, parent, add_entry, bcpup, btop); ++ if (err >= 0) { ++ if (d_really_is_negative(dentry)) { ++ au_set_h_dptr(dentry, btop, NULL); ++ au_set_dbtop(dentry, bcpup); ++ au_set_dbbot(dentry, bcpup); ++ } ++ AuDebugOn(add_entry ++ && !au_ftest_wrdir(args->flags, TMPFILE) ++ && !au_h_dptr(dentry, bcpup)); ++ } ++ ++out: ++ dput(parent); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_pin_hdir_unlock(struct au_pin *p) ++{ ++ if (p->hdir) ++ au_hn_inode_unlock(p->hdir); ++} ++ ++int au_pin_hdir_lock(struct au_pin *p) ++{ ++ int err; ++ ++ err = 0; ++ if (!p->hdir) ++ goto out; ++ ++ /* even if an error happens later, keep this lock */ ++ au_hn_inode_lock_nested(p->hdir, p->lsc_hi); ++ ++ err = -EBUSY; ++ if (unlikely(p->hdir->hi_inode != d_inode(p->h_parent))) ++ goto out; ++ ++ err = 0; ++ if (p->h_dentry) ++ err = au_h_verify(p->h_dentry, p->udba, p->hdir->hi_inode, ++ p->h_parent, p->br); ++ ++out: ++ return err; ++} ++ ++int au_pin_hdir_relock(struct au_pin *p) ++{ ++ int err, i; ++ struct inode *h_i; ++ struct dentry *h_d[] = { ++ p->h_dentry, ++ p->h_parent ++ }; ++ ++ err = au_pin_hdir_lock(p); ++ if (unlikely(err)) ++ goto out; ++ ++ for (i = 0; !err && i < sizeof(h_d)/sizeof(*h_d); i++) { ++ if (!h_d[i]) ++ continue; ++ if (d_is_positive(h_d[i])) { ++ h_i = d_inode(h_d[i]); ++ err = !h_i->i_nlink; ++ } ++ } ++ ++out: ++ return err; ++} ++ ++static void au_pin_hdir_set_owner(struct au_pin *p, struct task_struct *task) ++{ ++ atomic_long_set(&p->hdir->hi_inode->i_rwsem.owner, (long)task); ++} ++ ++void au_pin_hdir_acquire_nest(struct au_pin *p) ++{ ++ if (p->hdir) { ++ rwsem_acquire_nest(&p->hdir->hi_inode->i_rwsem.dep_map, ++ p->lsc_hi, 0, NULL, _RET_IP_); ++ au_pin_hdir_set_owner(p, current); ++ } ++} ++ ++void au_pin_hdir_release(struct au_pin *p) ++{ ++ if (p->hdir) { ++ au_pin_hdir_set_owner(p, p->task); ++ rwsem_release(&p->hdir->hi_inode->i_rwsem.dep_map, _RET_IP_); ++ } ++} ++ ++struct dentry *au_pinned_h_parent(struct au_pin *pin) ++{ ++ if (pin && pin->parent) ++ return au_h_dptr(pin->parent, pin->bindex); ++ return NULL; ++} ++ ++void au_unpin(struct au_pin *p) ++{ ++ if (p->hdir) ++ au_pin_hdir_unlock(p); ++ if (p->h_mnt && au_ftest_pin(p->flags, MNT_WRITE)) ++ vfsub_mnt_drop_write(p->h_mnt); ++ if (!p->hdir) ++ return; ++ ++ if (!au_ftest_pin(p->flags, DI_LOCKED)) ++ di_read_unlock(p->parent, AuLock_IR); ++ iput(p->hdir->hi_inode); ++ dput(p->parent); ++ p->parent = NULL; ++ p->hdir = NULL; ++ p->h_mnt = NULL; ++ /* do not clear p->task */ ++} ++ ++int au_do_pin(struct au_pin *p) ++{ ++ int err; ++ struct super_block *sb; ++ struct inode *h_dir; ++ ++ err = 0; ++ sb = p->dentry->d_sb; ++ p->br = au_sbr(sb, p->bindex); ++ if (IS_ROOT(p->dentry)) { ++ if (au_ftest_pin(p->flags, MNT_WRITE)) { ++ p->h_mnt = au_br_mnt(p->br); ++ err = vfsub_mnt_want_write(p->h_mnt); ++ if (unlikely(err)) { ++ au_fclr_pin(p->flags, MNT_WRITE); ++ goto out_err; ++ } ++ } ++ goto out; ++ } ++ ++ p->h_dentry = NULL; ++ if (p->bindex <= au_dbbot(p->dentry)) ++ p->h_dentry = au_h_dptr(p->dentry, p->bindex); ++ ++ p->parent = dget_parent(p->dentry); ++ if (!au_ftest_pin(p->flags, DI_LOCKED)) ++ di_read_lock(p->parent, AuLock_IR, p->lsc_di); ++ ++ h_dir = NULL; ++ p->h_parent = au_h_dptr(p->parent, p->bindex); ++ p->hdir = au_hi(d_inode(p->parent), p->bindex); ++ if (p->hdir) ++ h_dir = p->hdir->hi_inode; ++ ++ /* ++ * udba case, or ++ * if DI_LOCKED is not set, then p->parent may be different ++ * and h_parent can be NULL. ++ */ ++ if (unlikely(!p->hdir || !h_dir || !p->h_parent)) { ++ err = -EBUSY; ++ if (!au_ftest_pin(p->flags, DI_LOCKED)) ++ di_read_unlock(p->parent, AuLock_IR); ++ dput(p->parent); ++ p->parent = NULL; ++ goto out_err; ++ } ++ ++ if (au_ftest_pin(p->flags, MNT_WRITE)) { ++ p->h_mnt = au_br_mnt(p->br); ++ err = vfsub_mnt_want_write(p->h_mnt); ++ if (unlikely(err)) { ++ au_fclr_pin(p->flags, MNT_WRITE); ++ if (!au_ftest_pin(p->flags, DI_LOCKED)) ++ di_read_unlock(p->parent, AuLock_IR); ++ dput(p->parent); ++ p->parent = NULL; ++ goto out_err; ++ } ++ } ++ ++ au_igrab(h_dir); ++ err = au_pin_hdir_lock(p); ++ if (!err) ++ goto out; /* success */ ++ ++ au_unpin(p); ++ ++out_err: ++ pr_err("err %d\n", err); ++ err = au_busy_or_stale(); ++out: ++ return err; ++} ++ ++void au_pin_init(struct au_pin *p, struct dentry *dentry, ++ aufs_bindex_t bindex, int lsc_di, int lsc_hi, ++ unsigned int udba, unsigned char flags) ++{ ++ p->dentry = dentry; ++ p->udba = udba; ++ p->lsc_di = lsc_di; ++ p->lsc_hi = lsc_hi; ++ p->flags = flags; ++ p->bindex = bindex; ++ ++ p->parent = NULL; ++ p->hdir = NULL; ++ p->h_mnt = NULL; ++ ++ p->h_dentry = NULL; ++ p->h_parent = NULL; ++ p->br = NULL; ++ p->task = current; ++} ++ ++int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int udba, unsigned char flags) ++{ ++ au_pin_init(pin, dentry, bindex, AuLsc_DI_PARENT, AuLsc_I_PARENT2, ++ udba, flags); ++ return au_do_pin(pin); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * ->setattr() and ->getattr() are called in various cases. ++ * chmod, stat: dentry is revalidated. ++ * fchmod, fstat: file and dentry are not revalidated, additionally they may be ++ * unhashed. ++ * for ->setattr(), ia->ia_file is passed from ftruncate only. ++ */ ++/* todo: consolidate with do_refresh() and simple_reval_dpath() */ ++int au_reval_for_attr(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ struct dentry *parent; ++ ++ err = 0; ++ if (au_digen_test(dentry, sigen)) { ++ parent = dget_parent(dentry); ++ di_read_lock_parent(parent, AuLock_IR); ++ err = au_refresh_dentry(dentry, parent); ++ di_read_unlock(parent, AuLock_IR); ++ dput(parent); ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_pin_and_icpup(struct dentry *dentry, struct iattr *ia, ++ struct au_icpup_args *a) ++{ ++ int err; ++ loff_t sz; ++ aufs_bindex_t btop, ibtop; ++ struct dentry *hi_wh, *parent; ++ struct inode *inode; ++ struct au_wr_dir_args wr_dir_args = { ++ .force_btgt = -1, ++ .flags = 0 ++ }; ++ ++ if (d_is_dir(dentry)) ++ au_fset_wrdir(wr_dir_args.flags, ISDIR); ++ /* plink or hi_wh() case */ ++ btop = au_dbtop(dentry); ++ inode = d_inode(dentry); ++ ibtop = au_ibtop(inode); ++ if (btop != ibtop && !au_test_ro(inode->i_sb, ibtop, inode)) ++ wr_dir_args.force_btgt = ibtop; ++ err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args); ++ if (unlikely(err < 0)) ++ goto out; ++ a->btgt = err; ++ if (err != btop) ++ au_fset_icpup(a->flags, DID_CPUP); ++ ++ err = 0; ++ a->pin_flags = AuPin_MNT_WRITE; ++ parent = NULL; ++ if (!IS_ROOT(dentry)) { ++ au_fset_pin(a->pin_flags, DI_LOCKED); ++ parent = dget_parent(dentry); ++ di_write_lock_parent(parent); ++ } ++ ++ err = au_pin(&a->pin, dentry, a->btgt, a->udba, a->pin_flags); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ sz = -1; ++ a->h_path.dentry = au_h_dptr(dentry, btop); ++ a->h_inode = d_inode(a->h_path.dentry); ++ if (ia && (ia->ia_valid & ATTR_SIZE)) { ++ inode_lock_shared_nested(a->h_inode, AuLsc_I_CHILD); ++ if (ia->ia_size < i_size_read(a->h_inode)) ++ sz = ia->ia_size; ++ inode_unlock_shared(a->h_inode); ++ } ++ ++ hi_wh = NULL; ++ if (au_ftest_icpup(a->flags, DID_CPUP) && d_unlinked(dentry)) { ++ hi_wh = au_hi_wh(inode, a->btgt); ++ if (!hi_wh) { ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = a->btgt, ++ .bsrc = -1, ++ .len = sz, ++ .pin = &a->pin ++ }; ++ err = au_sio_cpup_wh(&cpg, /*file*/NULL); ++ if (unlikely(err)) ++ goto out_unlock; ++ hi_wh = au_hi_wh(inode, a->btgt); ++ /* todo: revalidate hi_wh? */ ++ } ++ } ++ ++ if (parent) { ++ au_pin_set_parent_lflag(&a->pin, /*lflag*/0); ++ di_downgrade_lock(parent, AuLock_IR); ++ dput(parent); ++ parent = NULL; ++ } ++ if (!au_ftest_icpup(a->flags, DID_CPUP)) ++ goto out; /* success */ ++ ++ if (!d_unhashed(dentry)) { ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = a->btgt, ++ .bsrc = btop, ++ .len = sz, ++ .pin = &a->pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ err = au_sio_cpup_simple(&cpg); ++ if (!err) ++ a->h_path.dentry = au_h_dptr(dentry, a->btgt); ++ } else if (!hi_wh) ++ a->h_path.dentry = au_h_dptr(dentry, a->btgt); ++ else ++ a->h_path.dentry = hi_wh; /* do not dget here */ ++ ++out_unlock: ++ a->h_inode = d_inode(a->h_path.dentry); ++ if (!err) ++ goto out; /* success */ ++ au_unpin(&a->pin); ++out_parent: ++ if (parent) { ++ di_write_unlock(parent); ++ dput(parent); ++ } ++out: ++ if (!err) ++ inode_lock_nested(a->h_inode, AuLsc_I_CHILD); ++ return err; ++} ++ ++static int aufs_setattr(struct user_namespace *userns, struct dentry *dentry, ++ struct iattr *ia) ++{ ++ int err; ++ struct inode *inode, *delegated; ++ struct super_block *sb; ++ struct file *file; ++ struct au_icpup_args *a; ++ struct user_namespace *h_userns; ++ ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ ++ err = setattr_prepare(userns, dentry, ia); ++ if (unlikely(err)) ++ goto out; ++ ++ err = -ENOMEM; ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ if (ia->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) ++ ia->ia_valid &= ~ATTR_MODE; ++ ++ file = NULL; ++ sb = dentry->d_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out_kfree; ++ ++ if (ia->ia_valid & ATTR_FILE) { ++ /* currently ftruncate(2) only */ ++ AuDebugOn(!d_is_reg(dentry)); ++ file = ia->ia_file; ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1, ++ /*fi_lsc*/0); ++ if (unlikely(err)) ++ goto out_si; ++ ia->ia_file = au_hf_top(file); ++ a->udba = AuOpt_UDBA_NONE; ++ } else { ++ /* fchmod() doesn't pass ia_file */ ++ a->udba = au_opt_udba(sb); ++ di_write_lock_child(dentry); ++ /* no d_unlinked(), to set UDBA_NONE for root */ ++ if (d_unhashed(dentry)) ++ a->udba = AuOpt_UDBA_NONE; ++ if (a->udba != AuOpt_UDBA_NONE) { ++ AuDebugOn(IS_ROOT(dentry)); ++ err = au_reval_for_attr(dentry, au_sigen(sb)); ++ if (unlikely(err)) ++ goto out_dentry; ++ } ++ } ++ ++ err = au_pin_and_icpup(dentry, ia, a); ++ if (unlikely(err < 0)) ++ goto out_dentry; ++ if (au_ftest_icpup(a->flags, DID_CPUP)) { ++ ia->ia_file = NULL; ++ ia->ia_valid &= ~ATTR_FILE; ++ } ++ ++ a->h_path.mnt = au_sbr_mnt(sb, a->btgt); ++ if ((ia->ia_valid & (ATTR_MODE | ATTR_CTIME)) ++ == (ATTR_MODE | ATTR_CTIME)) { ++ err = security_path_chmod(&a->h_path, ia->ia_mode); ++ if (unlikely(err)) ++ goto out_unlock; ++ } else if ((ia->ia_valid & (ATTR_UID | ATTR_GID)) ++ && (ia->ia_valid & ATTR_CTIME)) { ++ err = security_path_chown(&a->h_path, ia->ia_uid, ia->ia_gid); ++ if (unlikely(err)) ++ goto out_unlock; ++ } ++ ++ if (ia->ia_valid & ATTR_SIZE) { ++ struct file *f; ++ ++ if (ia->ia_size < i_size_read(inode)) ++ /* unmap only */ ++ truncate_setsize(inode, ia->ia_size); ++ ++ f = NULL; ++ if (ia->ia_valid & ATTR_FILE) ++ f = ia->ia_file; ++ inode_unlock(a->h_inode); ++ err = vfsub_trunc(&a->h_path, ia->ia_size, ia->ia_valid, f); ++ inode_lock_nested(a->h_inode, AuLsc_I_CHILD); ++ } else { ++ delegated = NULL; ++ while (1) { ++ err = vfsub_notify_change(&a->h_path, ia, &delegated); ++ if (delegated) { ++ err = break_deleg_wait(&delegated); ++ if (!err) ++ continue; ++ } ++ break; ++ } ++ } ++ /* ++ * regardless aufs 'acl' option setting. ++ * why don't all acl-aware fs call this func from their ->setattr()? ++ */ ++ if (!err && (ia->ia_valid & ATTR_MODE)) { ++ h_userns = mnt_user_ns(a->h_path.mnt); ++ err = vfsub_acl_chmod(h_userns, a->h_inode, ia->ia_mode); ++ } ++ if (!err) ++ au_cpup_attr_changeable(inode); ++ ++out_unlock: ++ inode_unlock(a->h_inode); ++ au_unpin(&a->pin); ++ if (unlikely(err)) ++ au_update_dbtop(dentry); ++out_dentry: ++ di_write_unlock(dentry); ++ if (file) { ++ fi_write_unlock(file); ++ ia->ia_file = file; ++ ia->ia_valid |= ATTR_FILE; ++ } ++out_si: ++ si_read_unlock(sb); ++out_kfree: ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++#if IS_ENABLED(CONFIG_AUFS_XATTR) || IS_ENABLED(CONFIG_FS_POSIX_ACL) ++static int au_h_path_to_set_attr(struct dentry *dentry, ++ struct au_icpup_args *a, struct path *h_path) ++{ ++ int err; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ a->udba = au_opt_udba(sb); ++ /* no d_unlinked(), to set UDBA_NONE for root */ ++ if (d_unhashed(dentry)) ++ a->udba = AuOpt_UDBA_NONE; ++ if (a->udba != AuOpt_UDBA_NONE) { ++ AuDebugOn(IS_ROOT(dentry)); ++ err = au_reval_for_attr(dentry, au_sigen(sb)); ++ if (unlikely(err)) ++ goto out; ++ } ++ err = au_pin_and_icpup(dentry, /*ia*/NULL, a); ++ if (unlikely(err < 0)) ++ goto out; ++ ++ h_path->dentry = a->h_path.dentry; ++ h_path->mnt = au_sbr_mnt(sb, a->btgt); ++ ++out: ++ return err; ++} ++ ++ssize_t au_sxattr(struct dentry *dentry, struct inode *inode, ++ struct au_sxattr *arg) ++{ ++ int err; ++ struct path h_path; ++ struct super_block *sb; ++ struct au_icpup_args *a; ++ struct inode *h_inode; ++ struct user_namespace *h_userns; ++ ++ IMustLock(inode); ++ ++ err = -ENOMEM; ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out_kfree; ++ ++ h_path.dentry = NULL; /* silence gcc */ ++ di_write_lock_child(dentry); ++ err = au_h_path_to_set_attr(dentry, a, &h_path); ++ if (unlikely(err)) ++ goto out_di; ++ h_userns = mnt_user_ns(h_path.mnt); ++ ++ inode_unlock(a->h_inode); ++ switch (arg->type) { ++ case AU_XATTR_SET: ++ AuDebugOn(d_is_negative(h_path.dentry)); ++ err = vfsub_setxattr(h_userns, h_path.dentry, ++ arg->u.set.name, arg->u.set.value, ++ arg->u.set.size, arg->u.set.flags); ++ break; ++ case AU_ACL_SET: ++ err = -EOPNOTSUPP; ++ h_inode = d_inode(h_path.dentry); ++ if (h_inode->i_op->set_acl) { ++ /* this will call posix_acl_update_mode */ ++ err = h_inode->i_op->set_acl(h_userns, h_inode, ++ arg->u.acl_set.acl, ++ arg->u.acl_set.type); ++ } ++ break; ++ } ++ if (!err) ++ au_cpup_attr_timesizes(inode); ++ ++ au_unpin(&a->pin); ++ if (unlikely(err)) ++ au_update_dbtop(dentry); ++ ++out_di: ++ di_write_unlock(dentry); ++ si_read_unlock(sb); ++out_kfree: ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++#endif ++ ++static void au_refresh_iattr(struct inode *inode, struct kstat *st, ++ unsigned int nlink) ++{ ++ unsigned int n; ++ ++ inode->i_mode = st->mode; ++ /* don't i_[ug]id_write() here */ ++ inode->i_uid = st->uid; ++ inode->i_gid = st->gid; ++ inode->i_atime = st->atime; ++ inode->i_mtime = st->mtime; ++ inode->i_ctime = st->ctime; ++ ++ au_cpup_attr_nlink(inode, /*force*/0); ++ if (S_ISDIR(inode->i_mode)) { ++ n = inode->i_nlink; ++ n -= nlink; ++ n += st->nlink; ++ smp_mb(); /* for i_nlink */ ++ /* 0 can happen */ ++ set_nlink(inode, n); ++ } ++ ++ spin_lock(&inode->i_lock); ++ inode->i_blocks = st->blocks; ++ i_size_write(inode, st->size); ++ spin_unlock(&inode->i_lock); ++} ++ ++/* ++ * common routine for aufs_getattr() and au_getxattr(). ++ * returns zero or negative (an error). ++ * @dentry will be read-locked in success. ++ */ ++int au_h_path_getattr(struct dentry *dentry, struct inode *inode, int force, ++ struct path *h_path, int locked) ++{ ++ int err; ++ unsigned int mnt_flags, sigen; ++ unsigned char udba_none; ++ aufs_bindex_t bindex; ++ struct super_block *sb, *h_sb; ++ ++ h_path->mnt = NULL; ++ h_path->dentry = NULL; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ mnt_flags = au_mntflags(sb); ++ udba_none = !!au_opt_test(mnt_flags, UDBA_NONE); ++ ++ if (unlikely(locked)) ++ goto body; /* skip locking dinfo */ ++ ++ /* support fstat(2) */ ++ if (!d_unlinked(dentry) && !udba_none) { ++ sigen = au_sigen(sb); ++ err = au_digen_test(dentry, sigen); ++ if (!err) { ++ di_read_lock_child(dentry, AuLock_IR); ++ err = au_dbrange_test(dentry); ++ if (unlikely(err)) { ++ di_read_unlock(dentry, AuLock_IR); ++ goto out; ++ } ++ } else { ++ AuDebugOn(IS_ROOT(dentry)); ++ di_write_lock_child(dentry); ++ err = au_dbrange_test(dentry); ++ if (!err) ++ err = au_reval_for_attr(dentry, sigen); ++ if (!err) ++ di_downgrade_lock(dentry, AuLock_IR); ++ else { ++ di_write_unlock(dentry); ++ goto out; ++ } ++ } ++ } else ++ di_read_lock_child(dentry, AuLock_IR); ++ ++body: ++ if (!inode) { ++ inode = d_inode(dentry); ++ if (unlikely(!inode)) ++ goto out; ++ } ++ bindex = au_ibtop(inode); ++ h_path->mnt = au_sbr_mnt(sb, bindex); ++ h_sb = h_path->mnt->mnt_sb; ++ if (!force ++ && !au_test_fs_bad_iattr(h_sb) ++ && udba_none) ++ goto out; /* success */ ++ ++ if (au_dbtop(dentry) == bindex) ++ h_path->dentry = au_h_dptr(dentry, bindex); ++ else if (au_opt_test(mnt_flags, PLINK) && au_plink_test(inode)) { ++ h_path->dentry = au_plink_lkup(inode, bindex); ++ if (IS_ERR(h_path->dentry)) ++ /* pretending success */ ++ h_path->dentry = NULL; ++ else ++ dput(h_path->dentry); ++ } ++ ++out: ++ return err; ++} ++ ++static int aufs_getattr(struct user_namespace *userns, const struct path *path, ++ struct kstat *st, u32 request, unsigned int query) ++{ ++ int err; ++ unsigned char positive; ++ struct path h_path; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ dentry = path->dentry; ++ inode = d_inode(dentry); ++ sb = dentry->d_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out; ++ err = au_h_path_getattr(dentry, /*inode*/NULL, /*force*/0, &h_path, ++ /*locked*/0); ++ if (unlikely(err)) ++ goto out_si; ++ if (unlikely(!h_path.dentry)) ++ /* illegally overlapped or something */ ++ goto out_fill; /* pretending success */ ++ ++ positive = d_is_positive(h_path.dentry); ++ if (positive) ++ /* no vfsub version */ ++ err = vfs_getattr(&h_path, st, request, query); ++ if (!err) { ++ if (positive) ++ au_refresh_iattr(inode, st, ++ d_inode(h_path.dentry)->i_nlink); ++ goto out_fill; /* success */ ++ } ++ AuTraceErr(err); ++ goto out_di; ++ ++out_fill: ++ generic_fillattr(userns, inode, st); ++out_di: ++ di_read_unlock(dentry, AuLock_IR); ++out_si: ++ si_read_unlock(sb); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static const char *aufs_get_link(struct dentry *dentry, struct inode *inode, ++ struct delayed_call *done) ++{ ++ const char *ret; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ int err; ++ aufs_bindex_t bindex; ++ ++ ret = NULL; /* suppress a warning */ ++ err = -ECHILD; ++ if (!dentry) ++ goto out; ++ ++ err = aufs_read_lock(dentry, AuLock_IR | AuLock_GEN); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_d_hashed_positive(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ err = -EINVAL; ++ inode = d_inode(dentry); ++ bindex = au_ibtop(inode); ++ h_inode = au_h_iptr(inode, bindex); ++ if (unlikely(!h_inode->i_op->get_link)) ++ goto out_unlock; ++ ++ err = -EBUSY; ++ h_dentry = NULL; ++ if (au_dbtop(dentry) <= bindex) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry) ++ dget(h_dentry); ++ } ++ if (!h_dentry) { ++ h_dentry = d_find_any_alias(h_inode); ++ if (IS_ERR(h_dentry)) { ++ err = PTR_ERR(h_dentry); ++ goto out_unlock; ++ } ++ } ++ if (unlikely(!h_dentry)) ++ goto out_unlock; ++ ++ err = 0; ++ AuDbg("%ps\n", h_inode->i_op->get_link); ++ AuDbgDentry(h_dentry); ++ ret = vfs_get_link(h_dentry, done); ++ dput(h_dentry); ++ if (IS_ERR(ret)) ++ err = PTR_ERR(ret); ++ ++out_unlock: ++ aufs_read_unlock(dentry, AuLock_IR); ++out: ++ if (unlikely(err)) ++ ret = ERR_PTR(err); ++ AuTraceErrPtr(ret); ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_is_special(struct inode *inode) ++{ ++ return (inode->i_mode & (S_IFBLK | S_IFCHR | S_IFIFO | S_IFSOCK)); ++} ++ ++static int aufs_update_time(struct inode *inode, struct timespec64 *ts, ++ int flags) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct super_block *sb; ++ struct inode *h_inode; ++ struct vfsmount *h_mnt; ++ ++ sb = inode->i_sb; ++ WARN_ONCE((flags & S_ATIME) && !IS_NOATIME(inode), ++ "unexpected s_flags 0x%lx", sb->s_flags); ++ ++ /* mmap_sem might be acquired already, cf. aufs_mmap() */ ++ lockdep_off(); ++ si_read_lock(sb, AuLock_FLUSH); ++ ii_write_lock_child(inode); ++ ++ err = 0; ++ bindex = au_ibtop(inode); ++ h_inode = au_h_iptr(inode, bindex); ++ if (!au_test_ro(sb, bindex, inode)) { ++ h_mnt = au_sbr_mnt(sb, bindex); ++ err = vfsub_mnt_want_write(h_mnt); ++ if (!err) { ++ err = vfsub_update_time(h_inode, ts, flags); ++ vfsub_mnt_drop_write(h_mnt); ++ } ++ } else if (au_is_special(h_inode)) { ++ /* ++ * Never copy-up here. ++ * These special files may already be opened and used for ++ * communicating. If we copied it up, then the communication ++ * would be corrupted. ++ */ ++ AuWarn1("timestamps for i%lu are ignored " ++ "since it is on readonly branch (hi%lu).\n", ++ inode->i_ino, h_inode->i_ino); ++ } else if (flags & ~S_ATIME) { ++ err = -EIO; ++ AuIOErr1("unexpected flags 0x%x\n", flags); ++ AuDebugOn(1); ++ } ++ ++ if (!err) ++ au_cpup_attr_timesizes(inode); ++ ii_write_unlock(inode); ++ si_read_unlock(sb); ++ lockdep_on(); ++ ++ if (!err && (flags & S_VERSION)) ++ inode_inc_iversion(inode); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* no getattr version will be set by module.c:aufs_init() */ ++struct inode_operations aufs_iop_nogetattr[AuIop_Last], ++ aufs_iop[] = { ++ [AuIop_SYMLINK] = { ++ .permission = aufs_permission, ++#ifdef CONFIG_FS_POSIX_ACL ++ .get_acl = aufs_get_acl, ++ .set_acl = aufs_set_acl, /* unsupport for symlink? */ ++#endif ++ ++ .setattr = aufs_setattr, ++ .getattr = aufs_getattr, ++ ++#ifdef CONFIG_AUFS_XATTR ++ .listxattr = aufs_listxattr, ++#endif ++ ++ .get_link = aufs_get_link, ++ ++ /* .update_time = aufs_update_time */ ++ }, ++ [AuIop_DIR] = { ++ .create = aufs_create, ++ .lookup = aufs_lookup, ++ .link = aufs_link, ++ .unlink = aufs_unlink, ++ .symlink = aufs_symlink, ++ .mkdir = aufs_mkdir, ++ .rmdir = aufs_rmdir, ++ .mknod = aufs_mknod, ++ .rename = aufs_rename, ++ ++ .permission = aufs_permission, ++#ifdef CONFIG_FS_POSIX_ACL ++ .get_acl = aufs_get_acl, ++ .set_acl = aufs_set_acl, ++#endif ++ ++ .setattr = aufs_setattr, ++ .getattr = aufs_getattr, ++ ++#ifdef CONFIG_AUFS_XATTR ++ .listxattr = aufs_listxattr, ++#endif ++ ++ .update_time = aufs_update_time, ++ .atomic_open = aufs_atomic_open, ++ .tmpfile = aufs_tmpfile ++ }, ++ [AuIop_OTHER] = { ++ .permission = aufs_permission, ++#ifdef CONFIG_FS_POSIX_ACL ++ .get_acl = aufs_get_acl, ++ .set_acl = aufs_set_acl, ++#endif ++ ++ .setattr = aufs_setattr, ++ .getattr = aufs_getattr, ++ ++#ifdef CONFIG_AUFS_XATTR ++ .listxattr = aufs_listxattr, ++#endif ++ ++ .update_time = aufs_update_time ++ } ++}; +diff -Naur null/fs/aufs/i_op_del.c linux-5.15.36/fs/aufs/i_op_del.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/i_op_del.c 2022-05-10 16:51:39.873744219 +0300 +@@ -0,0 +1,522 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * inode operations (del entry) ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* ++ * decide if a new whiteout for @dentry is necessary or not. ++ * when it is necessary, prepare the parent dir for the upper branch whose ++ * branch index is @bcpup for creation. the actual creation of the whiteout will ++ * be done by caller. ++ * return value: ++ * 0: wh is unnecessary ++ * plus: wh is necessary ++ * minus: error ++ */ ++int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup) ++{ ++ int need_wh, err; ++ aufs_bindex_t btop; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ btop = au_dbtop(dentry); ++ if (*bcpup < 0) { ++ *bcpup = btop; ++ if (au_test_ro(sb, btop, d_inode(dentry))) { ++ err = AuWbrCopyup(au_sbi(sb), dentry); ++ *bcpup = err; ++ if (unlikely(err < 0)) ++ goto out; ++ } ++ } else ++ AuDebugOn(btop < *bcpup ++ || au_test_ro(sb, *bcpup, d_inode(dentry))); ++ AuDbg("bcpup %d, btop %d\n", *bcpup, btop); ++ ++ if (*bcpup != btop) { ++ err = au_cpup_dirs(dentry, *bcpup); ++ if (unlikely(err)) ++ goto out; ++ need_wh = 1; ++ } else { ++ struct au_dinfo *dinfo, *tmp; ++ ++ need_wh = -ENOMEM; ++ dinfo = au_di(dentry); ++ tmp = au_di_alloc(sb, AuLsc_DI_TMP); ++ if (tmp) { ++ au_di_cp(tmp, dinfo); ++ au_di_swap(tmp, dinfo); ++ /* returns the number of positive dentries */ ++ need_wh = au_lkup_dentry(dentry, btop + 1, ++ /* AuLkup_IGNORE_PERM */ 0); ++ au_di_swap(tmp, dinfo); ++ au_rw_write_unlock(&tmp->di_rwsem); ++ au_di_free(tmp); ++ } ++ } ++ AuDbg("need_wh %d\n", need_wh); ++ err = need_wh; ++ ++out: ++ return err; ++} ++ ++/* ++ * simple tests for the del-entry operations. ++ * following the checks in vfs, plus the parent-child relationship. ++ */ ++int au_may_del(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, int isdir) ++{ ++ int err; ++ umode_t h_mode; ++ struct dentry *h_dentry, *h_latest; ++ struct inode *h_inode; ++ struct path h_ppath; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct user_namespace *h_userns; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (d_really_is_positive(dentry)) { ++ err = -ENOENT; ++ if (unlikely(d_is_negative(h_dentry))) ++ goto out; ++ h_inode = d_inode(h_dentry); ++ if (unlikely(!h_inode->i_nlink)) ++ goto out; ++ ++ h_mode = h_inode->i_mode; ++ if (!isdir) { ++ err = -EISDIR; ++ if (unlikely(S_ISDIR(h_mode))) ++ goto out; ++ } else if (unlikely(!S_ISDIR(h_mode))) { ++ err = -ENOTDIR; ++ goto out; ++ } ++ } else { ++ /* rename(2) case */ ++ err = -EIO; ++ if (unlikely(d_is_positive(h_dentry))) ++ goto out; ++ } ++ ++ err = -ENOENT; ++ /* expected parent dir is locked */ ++ if (unlikely(h_parent != h_dentry->d_parent)) ++ goto out; ++ err = 0; ++ ++ /* ++ * rmdir a dir may break the consistency on some filesystem. ++ * let's try heavy test. ++ */ ++ err = -EACCES; ++ sb = dentry->d_sb; ++ br = au_sbr(sb, bindex); ++ h_userns = au_br_userns(br); ++ if (unlikely(!au_opt_test(au_mntflags(sb), DIRPERM1) ++ && au_test_h_perm(h_userns, d_inode(h_parent), ++ MAY_EXEC | MAY_WRITE))) ++ goto out; ++ ++ h_ppath.dentry = h_parent; ++ h_ppath.mnt = au_br_mnt(br); ++ h_latest = au_sio_lkup_one(h_userns, &dentry->d_name, &h_ppath); ++ err = -EIO; ++ if (IS_ERR(h_latest)) ++ goto out; ++ if (h_latest == h_dentry) ++ err = 0; ++ dput(h_latest); ++ ++out: ++ return err; ++} ++ ++/* ++ * decide the branch where we operate for @dentry. the branch index will be set ++ * @rbcpup. after deciding it, 'pin' it and store the timestamps of the parent ++ * dir for reverting. ++ * when a new whiteout is necessary, create it. ++ */ ++static struct dentry* ++lock_hdir_create_wh(struct dentry *dentry, int isdir, aufs_bindex_t *rbcpup, ++ struct au_dtime *dt, struct au_pin *pin) ++{ ++ struct dentry *wh_dentry; ++ struct super_block *sb; ++ struct path h_path; ++ int err, need_wh; ++ unsigned int udba; ++ aufs_bindex_t bcpup; ++ ++ need_wh = au_wr_dir_need_wh(dentry, isdir, rbcpup); ++ wh_dentry = ERR_PTR(need_wh); ++ if (unlikely(need_wh < 0)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ udba = au_opt_udba(sb); ++ bcpup = *rbcpup; ++ err = au_pin(pin, dentry, bcpup, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ h_path.dentry = au_pinned_h_parent(pin); ++ if (udba != AuOpt_UDBA_NONE ++ && au_dbtop(dentry) == bcpup) { ++ err = au_may_del(dentry, bcpup, h_path.dentry, isdir); ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_unpin; ++ } ++ ++ h_path.mnt = au_sbr_mnt(sb, bcpup); ++ au_dtime_store(dt, au_pinned_parent(pin), &h_path); ++ wh_dentry = NULL; ++ if (!need_wh) ++ goto out; /* success, no need to create whiteout */ ++ ++ wh_dentry = au_wh_create(dentry, bcpup, h_path.dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_unpin; ++ ++ /* returns with the parent is locked and wh_dentry is dget-ed */ ++ goto out; /* success */ ++ ++out_unpin: ++ au_unpin(pin); ++out: ++ return wh_dentry; ++} ++ ++/* ++ * when removing a dir, rename it to a unique temporary whiteout-ed name first ++ * in order to be revertible and save time for removing many child whiteouts ++ * under the dir. ++ * returns 1 when there are too many child whiteout and caller should remove ++ * them asynchronously. returns 0 when the number of children is enough small to ++ * remove now or the branch fs is a remote fs. ++ * otherwise return an error. ++ */ ++static int renwh_and_rmdir(struct dentry *dentry, aufs_bindex_t bindex, ++ struct au_nhash *whlist, struct inode *dir) ++{ ++ int rmdir_later, err, dirwh; ++ struct dentry *h_dentry; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ sb = dentry->d_sb; ++ SiMustAnyLock(sb); ++ h_dentry = au_h_dptr(dentry, bindex); ++ err = au_whtmp_ren(h_dentry, au_sbr(sb, bindex)); ++ if (unlikely(err)) ++ goto out; ++ ++ /* stop monitoring */ ++ inode = d_inode(dentry); ++ au_hn_free(au_hi(inode, bindex)); ++ ++ if (!au_test_fs_remote(h_dentry->d_sb)) { ++ dirwh = au_sbi(sb)->si_dirwh; ++ rmdir_later = (dirwh <= 1); ++ if (!rmdir_later) ++ rmdir_later = au_nhash_test_longer_wh(whlist, bindex, ++ dirwh); ++ if (rmdir_later) ++ return rmdir_later; ++ } ++ ++ err = au_whtmp_rmdir(dir, bindex, h_dentry, whlist); ++ if (unlikely(err)) { ++ AuIOErr("rmdir %pd, b%d failed, %d. ignored\n", ++ h_dentry, bindex, err); ++ err = 0; ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * final procedure for deleting a entry. ++ * maintain dentry and iattr. ++ */ ++static void epilog(struct inode *dir, struct dentry *dentry, ++ aufs_bindex_t bindex) ++{ ++ struct inode *inode; ++ ++ inode = d_inode(dentry); ++ d_drop(dentry); ++ inode->i_ctime = dir->i_ctime; ++ ++ au_dir_ts(dir, bindex); ++ inode_inc_iversion(dir); ++} ++ ++/* ++ * when an error happened, remove the created whiteout and revert everything. ++ */ ++static int do_revert(int err, struct inode *dir, aufs_bindex_t bindex, ++ aufs_bindex_t bwh, struct dentry *wh_dentry, ++ struct dentry *dentry, struct au_dtime *dt) ++{ ++ int rerr; ++ struct path h_path = { ++ .dentry = wh_dentry, ++ .mnt = au_sbr_mnt(dir->i_sb, bindex) ++ }; ++ ++ rerr = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path, dentry); ++ if (!rerr) { ++ au_set_dbwh(dentry, bwh); ++ au_dtime_revert(dt); ++ return 0; ++ } ++ ++ AuIOErr("%pd reverting whiteout failed(%d, %d)\n", dentry, err, rerr); ++ return -EIO; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int aufs_unlink(struct inode *dir, struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t bwh, bindex, btop; ++ struct inode *inode, *h_dir, *delegated; ++ struct dentry *parent, *wh_dentry; ++ /* to reduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct au_pin pin; ++ struct path h_path; ++ } *a; ++ ++ IMustLock(dir); ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_free; ++ err = au_d_hashed_positive(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ err = -EISDIR; ++ if (unlikely(d_is_dir(dentry))) ++ goto out_unlock; /* possible? */ ++ ++ btop = au_dbtop(dentry); ++ bwh = au_dbwh(dentry); ++ bindex = -1; ++ parent = dentry->d_parent; /* dir inode is locked */ ++ di_write_lock_parent(parent); ++ wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/0, &bindex, &a->dt, ++ &a->pin); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ a->h_path.mnt = au_sbr_mnt(dentry->d_sb, btop); ++ a->h_path.dentry = au_h_dptr(dentry, btop); ++ dget(a->h_path.dentry); ++ if (bindex == btop) { ++ h_dir = au_pinned_h_dir(&a->pin); ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, &a->h_path, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ } else { ++ /* dir inode is locked */ ++ h_dir = d_inode(wh_dentry->d_parent); ++ IMustLock(h_dir); ++ err = 0; ++ } ++ ++ if (!err) { ++ vfsub_drop_nlink(inode); ++ epilog(dir, dentry, bindex); ++ ++ /* update target timestamps */ ++ if (bindex == btop) { ++ vfsub_update_h_iattr(&a->h_path, /*did*/NULL); ++ /*ignore*/ ++ inode->i_ctime = d_inode(a->h_path.dentry)->i_ctime; ++ } else ++ /* todo: this timestamp may be reverted later */ ++ inode->i_ctime = h_dir->i_ctime; ++ goto out_unpin; /* success */ ++ } ++ ++ /* revert */ ++ if (wh_dentry) { ++ int rerr; ++ ++ rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry, ++ &a->dt); ++ if (rerr) ++ err = rerr; ++ } ++ ++out_unpin: ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++ dput(a->h_path.dentry); ++out_parent: ++ di_write_unlock(parent); ++out_unlock: ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ au_kfree_rcu(a); ++out: ++ return err; ++} ++ ++int aufs_rmdir(struct inode *dir, struct dentry *dentry) ++{ ++ int err, rmdir_later; ++ aufs_bindex_t bwh, bindex, btop; ++ struct inode *inode; ++ struct dentry *parent, *wh_dentry, *h_dentry; ++ struct au_whtmp_rmdir *args; ++ /* to reduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct au_pin pin; ++ } *a; ++ ++ IMustLock(dir); ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_free; ++ err = au_alive_dir(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ err = -ENOTDIR; ++ if (unlikely(!d_is_dir(dentry))) ++ goto out_unlock; /* possible? */ ++ ++ err = -ENOMEM; ++ args = au_whtmp_rmdir_alloc(dir->i_sb, GFP_NOFS); ++ if (unlikely(!args)) ++ goto out_unlock; ++ ++ parent = dentry->d_parent; /* dir inode is locked */ ++ di_write_lock_parent(parent); ++ err = au_test_empty(dentry, &args->whlist); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ btop = au_dbtop(dentry); ++ bwh = au_dbwh(dentry); ++ bindex = -1; ++ wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/1, &bindex, &a->dt, ++ &a->pin); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ h_dentry = au_h_dptr(dentry, btop); ++ dget(h_dentry); ++ rmdir_later = 0; ++ if (bindex == btop) { ++ err = renwh_and_rmdir(dentry, btop, &args->whlist, dir); ++ if (err > 0) { ++ rmdir_later = err; ++ err = 0; ++ } ++ } else { ++ /* stop monitoring */ ++ au_hn_free(au_hi(inode, btop)); ++ ++ /* dir inode is locked */ ++ IMustLock(d_inode(wh_dentry->d_parent)); ++ err = 0; ++ } ++ ++ if (!err) { ++ vfsub_dead_dir(inode); ++ au_set_dbdiropq(dentry, -1); ++ epilog(dir, dentry, bindex); ++ ++ if (rmdir_later) { ++ au_whtmp_kick_rmdir(dir, btop, h_dentry, args); ++ args = NULL; ++ } ++ ++ goto out_unpin; /* success */ ++ } ++ ++ /* revert */ ++ AuLabel(revert); ++ if (wh_dentry) { ++ int rerr; ++ ++ rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry, ++ &a->dt); ++ if (rerr) ++ err = rerr; ++ } ++ ++out_unpin: ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++ dput(h_dentry); ++out_parent: ++ di_write_unlock(parent); ++ if (args) ++ au_whtmp_rmdir_free(args); ++out_unlock: ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} +diff -Naur null/fs/aufs/i_op_ren.c linux-5.15.36/fs/aufs/i_op_ren.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/i_op_ren.c 2022-05-10 16:51:39.873744219 +0300 +@@ -0,0 +1,1257 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * inode operation (rename entry) ++ * todo: this is crazy monster ++ */ ++ ++#include ++#include "aufs.h" ++ ++enum { AuSRC, AuDST, AuSrcDst }; ++enum { AuPARENT, AuCHILD, AuParentChild }; ++ ++#define AuRen_ISDIR_SRC 1 ++#define AuRen_ISDIR_DST (1 << 1) ++#define AuRen_ISSAMEDIR (1 << 2) ++#define AuRen_WHSRC (1 << 3) ++#define AuRen_WHDST (1 << 4) ++#define AuRen_MNT_WRITE (1 << 5) ++#define AuRen_DT_DSTDIR (1 << 6) ++#define AuRen_DIROPQ_SRC (1 << 7) ++#define AuRen_DIROPQ_DST (1 << 8) ++#define AuRen_DIRREN (1 << 9) ++#define AuRen_DROPPED_SRC (1 << 10) ++#define AuRen_DROPPED_DST (1 << 11) ++#define au_ftest_ren(flags, name) ((flags) & AuRen_##name) ++#define au_fset_ren(flags, name) \ ++ do { (flags) |= AuRen_##name; } while (0) ++#define au_fclr_ren(flags, name) \ ++ do { (flags) &= ~AuRen_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_DIRREN ++#undef AuRen_DIRREN ++#define AuRen_DIRREN 0 ++#endif ++ ++struct au_ren_args { ++ struct { ++ struct dentry *dentry, *h_dentry, *parent, *h_parent, ++ *wh_dentry; ++ struct inode *dir, *inode; ++ struct au_hinode *hdir, *hinode; ++ struct au_dtime dt[AuParentChild]; ++ aufs_bindex_t btop, bdiropq; ++ } sd[AuSrcDst]; ++ ++#define src_dentry sd[AuSRC].dentry ++#define src_dir sd[AuSRC].dir ++#define src_inode sd[AuSRC].inode ++#define src_h_dentry sd[AuSRC].h_dentry ++#define src_parent sd[AuSRC].parent ++#define src_h_parent sd[AuSRC].h_parent ++#define src_wh_dentry sd[AuSRC].wh_dentry ++#define src_hdir sd[AuSRC].hdir ++#define src_hinode sd[AuSRC].hinode ++#define src_h_dir sd[AuSRC].hdir->hi_inode ++#define src_dt sd[AuSRC].dt ++#define src_btop sd[AuSRC].btop ++#define src_bdiropq sd[AuSRC].bdiropq ++ ++#define dst_dentry sd[AuDST].dentry ++#define dst_dir sd[AuDST].dir ++#define dst_inode sd[AuDST].inode ++#define dst_h_dentry sd[AuDST].h_dentry ++#define dst_parent sd[AuDST].parent ++#define dst_h_parent sd[AuDST].h_parent ++#define dst_wh_dentry sd[AuDST].wh_dentry ++#define dst_hdir sd[AuDST].hdir ++#define dst_hinode sd[AuDST].hinode ++#define dst_h_dir sd[AuDST].hdir->hi_inode ++#define dst_dt sd[AuDST].dt ++#define dst_btop sd[AuDST].btop ++#define dst_bdiropq sd[AuDST].bdiropq ++ ++ struct dentry *h_trap; ++ struct au_branch *br; ++ struct path h_path; ++ struct au_nhash whlist; ++ aufs_bindex_t btgt, src_bwh; ++ ++ struct { ++ unsigned short auren_flags; ++ unsigned char flags; /* syscall parameter */ ++ unsigned char exchange; ++ } __packed; ++ ++ struct au_whtmp_rmdir *thargs; ++ struct dentry *h_dst; ++ struct au_hinode *h_root; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * functions for reverting. ++ * when an error happened in a single rename systemcall, we should revert ++ * everything as if nothing happened. ++ * we don't need to revert the copied-up/down the parent dir since they are ++ * harmless. ++ */ ++ ++#define RevertFailure(fmt, ...) do { \ ++ AuIOErr("revert failure: " fmt " (%d, %d)\n", \ ++ ##__VA_ARGS__, err, rerr); \ ++ err = -EIO; \ ++} while (0) ++ ++static void au_ren_do_rev_diropq(int err, struct au_ren_args *a, int idx) ++{ ++ int rerr; ++ struct dentry *d; ++#define src_or_dst(member) a->sd[idx].member ++ ++ d = src_or_dst(dentry); /* {src,dst}_dentry */ ++ au_hn_inode_lock_nested(src_or_dst(hinode), AuLsc_I_CHILD); ++ rerr = au_diropq_remove(d, a->btgt); ++ au_hn_inode_unlock(src_or_dst(hinode)); ++ au_set_dbdiropq(d, src_or_dst(bdiropq)); ++ if (rerr) ++ RevertFailure("remove diropq %pd", d); ++ ++#undef src_or_dst_ ++} ++ ++static void au_ren_rev_diropq(int err, struct au_ren_args *a) ++{ ++ if (au_ftest_ren(a->auren_flags, DIROPQ_SRC)) ++ au_ren_do_rev_diropq(err, a, AuSRC); ++ if (au_ftest_ren(a->auren_flags, DIROPQ_DST)) ++ au_ren_do_rev_diropq(err, a, AuDST); ++} ++ ++static void au_ren_rev_rename(int err, struct au_ren_args *a) ++{ ++ int rerr; ++ struct inode *delegated; ++ struct path h_ppath = { ++ .dentry = a->src_h_parent, ++ .mnt = a->h_path.mnt ++ }; ++ ++ a->h_path.dentry = vfsub_lkup_one(&a->src_dentry->d_name, &h_ppath); ++ rerr = PTR_ERR(a->h_path.dentry); ++ if (IS_ERR(a->h_path.dentry)) { ++ RevertFailure("lkup one %pd", a->src_dentry); ++ return; ++ } ++ ++ delegated = NULL; ++ rerr = vfsub_rename(a->dst_h_dir, ++ au_h_dptr(a->src_dentry, a->btgt), ++ a->src_h_dir, &a->h_path, &delegated, a->flags); ++ if (unlikely(rerr == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ d_drop(a->h_path.dentry); ++ dput(a->h_path.dentry); ++ /* au_set_h_dptr(a->src_dentry, a->btgt, NULL); */ ++ if (rerr) ++ RevertFailure("rename %pd", a->src_dentry); ++} ++ ++static void au_ren_rev_whtmp(int err, struct au_ren_args *a) ++{ ++ int rerr; ++ struct inode *delegated; ++ struct path h_ppath = { ++ .dentry = a->dst_h_parent, ++ .mnt = a->h_path.mnt ++ }; ++ ++ a->h_path.dentry = vfsub_lkup_one(&a->dst_dentry->d_name, &h_ppath); ++ rerr = PTR_ERR(a->h_path.dentry); ++ if (IS_ERR(a->h_path.dentry)) { ++ RevertFailure("lkup one %pd", a->dst_dentry); ++ return; ++ } ++ if (d_is_positive(a->h_path.dentry)) { ++ d_drop(a->h_path.dentry); ++ dput(a->h_path.dentry); ++ return; ++ } ++ ++ delegated = NULL; ++ rerr = vfsub_rename(a->dst_h_dir, a->h_dst, a->dst_h_dir, &a->h_path, ++ &delegated, a->flags); ++ if (unlikely(rerr == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ d_drop(a->h_path.dentry); ++ dput(a->h_path.dentry); ++ if (!rerr) ++ au_set_h_dptr(a->dst_dentry, a->btgt, dget(a->h_dst)); ++ else ++ RevertFailure("rename %pd", a->h_dst); ++} ++ ++static void au_ren_rev_whsrc(int err, struct au_ren_args *a) ++{ ++ int rerr; ++ ++ a->h_path.dentry = a->src_wh_dentry; ++ rerr = au_wh_unlink_dentry(a->src_h_dir, &a->h_path, a->src_dentry); ++ au_set_dbwh(a->src_dentry, a->src_bwh); ++ if (rerr) ++ RevertFailure("unlink %pd", a->src_wh_dentry); ++} ++#undef RevertFailure ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * when we have to copyup the renaming entry, do it with the rename-target name ++ * in order to minimize the cost (the later actual rename is unnecessary). ++ * otherwise rename it on the target branch. ++ */ ++static int au_ren_or_cpup(struct au_ren_args *a) ++{ ++ int err; ++ struct dentry *d; ++ struct inode *delegated; ++ ++ d = a->src_dentry; ++ if (au_dbtop(d) == a->btgt) { ++ a->h_path.dentry = a->dst_h_dentry; ++ AuDebugOn(au_dbtop(d) != a->btgt); ++ delegated = NULL; ++ err = vfsub_rename(a->src_h_dir, au_h_dptr(d, a->btgt), ++ a->dst_h_dir, &a->h_path, &delegated, ++ a->flags); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ } else ++ BUG(); ++ ++ if (!err && a->h_dst) ++ /* it will be set to dinfo later */ ++ dget(a->h_dst); ++ ++ return err; ++} ++ ++/* cf. aufs_rmdir() */ ++static int au_ren_del_whtmp(struct au_ren_args *a) ++{ ++ int err; ++ struct inode *dir; ++ ++ dir = a->dst_dir; ++ SiMustAnyLock(dir->i_sb); ++ if (!au_nhash_test_longer_wh(&a->whlist, a->btgt, ++ au_sbi(dir->i_sb)->si_dirwh) ++ || au_test_fs_remote(a->h_dst->d_sb)) { ++ err = au_whtmp_rmdir(dir, a->btgt, a->h_dst, &a->whlist); ++ if (unlikely(err)) ++ pr_warn("failed removing whtmp dir %pd (%d), " ++ "ignored.\n", a->h_dst, err); ++ } else { ++ au_nhash_wh_free(&a->thargs->whlist); ++ a->thargs->whlist = a->whlist; ++ a->whlist.nh_num = 0; ++ au_whtmp_kick_rmdir(dir, a->btgt, a->h_dst, a->thargs); ++ dput(a->h_dst); ++ a->thargs = NULL; ++ } ++ ++ return 0; ++} ++ ++/* make it 'opaque' dir. */ ++static int au_ren_do_diropq(struct au_ren_args *a, int idx) ++{ ++ int err; ++ struct dentry *d, *diropq; ++#define src_or_dst(member) a->sd[idx].member ++ ++ err = 0; ++ d = src_or_dst(dentry); /* {src,dst}_dentry */ ++ src_or_dst(bdiropq) = au_dbdiropq(d); ++ src_or_dst(hinode) = au_hi(src_or_dst(inode), a->btgt); ++ au_hn_inode_lock_nested(src_or_dst(hinode), AuLsc_I_CHILD); ++ diropq = au_diropq_create(d, a->btgt); ++ au_hn_inode_unlock(src_or_dst(hinode)); ++ if (IS_ERR(diropq)) ++ err = PTR_ERR(diropq); ++ else ++ dput(diropq); ++ ++#undef src_or_dst_ ++ return err; ++} ++ ++static int au_ren_diropq(struct au_ren_args *a) ++{ ++ int err; ++ unsigned char always; ++ struct dentry *d; ++ ++ err = 0; ++ d = a->dst_dentry; /* already renamed on the branch */ ++ always = !!au_opt_test(au_mntflags(d->d_sb), ALWAYS_DIROPQ); ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC) ++ && !au_ftest_ren(a->auren_flags, DIRREN) ++ && a->btgt != au_dbdiropq(a->src_dentry) ++ && (a->dst_wh_dentry ++ || a->btgt <= au_dbdiropq(d) ++ /* hide the lower to keep xino */ ++ /* the lowers may not be a dir, but we hide them anyway */ ++ || a->btgt < au_dbbot(d) ++ || always)) { ++ AuDbg("here\n"); ++ err = au_ren_do_diropq(a, AuSRC); ++ if (unlikely(err)) ++ goto out; ++ au_fset_ren(a->auren_flags, DIROPQ_SRC); ++ } ++ if (!a->exchange) ++ goto out; /* success */ ++ ++ d = a->src_dentry; /* already renamed on the branch */ ++ if (au_ftest_ren(a->auren_flags, ISDIR_DST) ++ && a->btgt != au_dbdiropq(a->dst_dentry) ++ && (a->btgt < au_dbdiropq(d) ++ || a->btgt < au_dbbot(d) ++ || always)) { ++ AuDbgDentry(a->src_dentry); ++ AuDbgDentry(a->dst_dentry); ++ err = au_ren_do_diropq(a, AuDST); ++ if (unlikely(err)) ++ goto out_rev_src; ++ au_fset_ren(a->auren_flags, DIROPQ_DST); ++ } ++ goto out; /* success */ ++ ++out_rev_src: ++ AuDbg("err %d, reverting src\n", err); ++ au_ren_rev_diropq(err, a); ++out: ++ return err; ++} ++ ++static int do_rename(struct au_ren_args *a) ++{ ++ int err; ++ struct dentry *d, *h_d; ++ ++ if (!a->exchange) { ++ /* prepare workqueue args for asynchronous rmdir */ ++ h_d = a->dst_h_dentry; ++ if (au_ftest_ren(a->auren_flags, ISDIR_DST) ++ /* && !au_ftest_ren(a->auren_flags, DIRREN) */ ++ && d_is_positive(h_d)) { ++ err = -ENOMEM; ++ a->thargs = au_whtmp_rmdir_alloc(a->src_dentry->d_sb, ++ GFP_NOFS); ++ if (unlikely(!a->thargs)) ++ goto out; ++ a->h_dst = dget(h_d); ++ } ++ ++ /* create whiteout for src_dentry */ ++ if (au_ftest_ren(a->auren_flags, WHSRC)) { ++ a->src_bwh = au_dbwh(a->src_dentry); ++ AuDebugOn(a->src_bwh >= 0); ++ a->src_wh_dentry = au_wh_create(a->src_dentry, a->btgt, ++ a->src_h_parent); ++ err = PTR_ERR(a->src_wh_dentry); ++ if (IS_ERR(a->src_wh_dentry)) ++ goto out_thargs; ++ } ++ ++ /* lookup whiteout for dentry */ ++ if (au_ftest_ren(a->auren_flags, WHDST)) { ++ h_d = au_wh_lkup(a->dst_h_parent, ++ &a->dst_dentry->d_name, a->br); ++ err = PTR_ERR(h_d); ++ if (IS_ERR(h_d)) ++ goto out_whsrc; ++ if (d_is_negative(h_d)) ++ dput(h_d); ++ else ++ a->dst_wh_dentry = h_d; ++ } ++ ++ /* rename dentry to tmpwh */ ++ if (a->thargs) { ++ err = au_whtmp_ren(a->dst_h_dentry, a->br); ++ if (unlikely(err)) ++ goto out_whdst; ++ ++ d = a->dst_dentry; ++ au_set_h_dptr(d, a->btgt, NULL); ++ err = au_lkup_neg(d, a->btgt, /*wh*/0); ++ if (unlikely(err)) ++ goto out_whtmp; ++ a->dst_h_dentry = au_h_dptr(d, a->btgt); ++ } ++ } ++ ++ BUG_ON(d_is_positive(a->dst_h_dentry) && a->src_btop != a->btgt); ++#if 0 /* debugging */ ++ BUG_ON(!au_ftest_ren(a->auren_flags, DIRREN) ++ && d_is_positive(a->dst_h_dentry) ++ && a->src_btop != a->btgt); ++#endif ++ ++ /* rename by vfs_rename or cpup */ ++ err = au_ren_or_cpup(a); ++ if (unlikely(err)) ++ /* leave the copied-up one */ ++ goto out_whtmp; ++ ++ /* make dir opaque */ ++ err = au_ren_diropq(a); ++ if (unlikely(err)) ++ goto out_rename; ++ ++ /* update target timestamps */ ++ if (a->exchange) { ++ AuDebugOn(au_dbtop(a->dst_dentry) != a->btgt); ++ a->h_path.dentry = au_h_dptr(a->dst_dentry, a->btgt); ++ vfsub_update_h_iattr(&a->h_path, /*did*/NULL); /*ignore*/ ++ a->dst_inode->i_ctime = d_inode(a->h_path.dentry)->i_ctime; ++ } ++ AuDebugOn(au_dbtop(a->src_dentry) != a->btgt); ++ a->h_path.dentry = au_h_dptr(a->src_dentry, a->btgt); ++ vfsub_update_h_iattr(&a->h_path, /*did*/NULL); /*ignore*/ ++ a->src_inode->i_ctime = d_inode(a->h_path.dentry)->i_ctime; ++ ++ if (!a->exchange) { ++ /* remove whiteout for dentry */ ++ if (a->dst_wh_dentry) { ++ a->h_path.dentry = a->dst_wh_dentry; ++ err = au_wh_unlink_dentry(a->dst_h_dir, &a->h_path, ++ a->dst_dentry); ++ if (unlikely(err)) ++ goto out_diropq; ++ } ++ ++ /* remove whtmp */ ++ if (a->thargs) ++ au_ren_del_whtmp(a); /* ignore this error */ ++ ++ au_fhsm_wrote(a->src_dentry->d_sb, a->btgt, /*force*/0); ++ } ++ err = 0; ++ goto out_success; ++ ++out_diropq: ++ au_ren_rev_diropq(err, a); ++out_rename: ++ au_ren_rev_rename(err, a); ++ dput(a->h_dst); ++out_whtmp: ++ if (a->thargs) ++ au_ren_rev_whtmp(err, a); ++out_whdst: ++ dput(a->dst_wh_dentry); ++ a->dst_wh_dentry = NULL; ++out_whsrc: ++ if (a->src_wh_dentry) ++ au_ren_rev_whsrc(err, a); ++out_success: ++ dput(a->src_wh_dentry); ++ dput(a->dst_wh_dentry); ++out_thargs: ++ if (a->thargs) { ++ dput(a->h_dst); ++ au_whtmp_rmdir_free(a->thargs); ++ a->thargs = NULL; ++ } ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * test if @dentry dir can be rename destination or not. ++ * success means, it is a logically empty dir. ++ */ ++static int may_rename_dstdir(struct dentry *dentry, struct au_nhash *whlist) ++{ ++ return au_test_empty(dentry, whlist); ++} ++ ++/* ++ * test if @a->src_dentry dir can be rename source or not. ++ * if it can, return 0. ++ * success means, ++ * - it is a logically empty dir. ++ * - or, it exists on writable branch and has no children including whiteouts ++ * on the lower branch unless DIRREN is on. ++ */ ++static int may_rename_srcdir(struct au_ren_args *a) ++{ ++ int err; ++ unsigned int rdhash; ++ aufs_bindex_t btop, btgt; ++ struct dentry *dentry; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ ++ dentry = a->src_dentry; ++ sb = dentry->d_sb; ++ sbinfo = au_sbi(sb); ++ if (au_opt_test(sbinfo->si_mntflags, DIRREN)) ++ au_fset_ren(a->auren_flags, DIRREN); ++ ++ btgt = a->btgt; ++ btop = au_dbtop(dentry); ++ if (btop != btgt) { ++ struct au_nhash whlist; ++ ++ SiMustAnyLock(sb); ++ rdhash = sbinfo->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, ++ dentry)); ++ err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_test_empty(dentry, &whlist); ++ au_nhash_wh_free(&whlist); ++ goto out; ++ } ++ ++ if (btop == au_dbtaildir(dentry)) ++ return 0; /* success */ ++ ++ err = au_test_empty_lower(dentry); ++ ++out: ++ if (err == -ENOTEMPTY) { ++ if (au_ftest_ren(a->auren_flags, DIRREN)) { ++ err = 0; ++ } else { ++ AuWarn1("renaming dir who has child(ren) on multiple " ++ "branches, is not supported\n"); ++ err = -EXDEV; ++ } ++ } ++ return err; ++} ++ ++/* side effect: sets whlist and h_dentry */ ++static int au_ren_may_dir(struct au_ren_args *a) ++{ ++ int err; ++ unsigned int rdhash; ++ struct dentry *d; ++ ++ d = a->dst_dentry; ++ SiMustAnyLock(d->d_sb); ++ ++ err = 0; ++ if (au_ftest_ren(a->auren_flags, ISDIR_DST) && a->dst_inode) { ++ rdhash = au_sbi(d->d_sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, d)); ++ err = au_nhash_alloc(&a->whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ ++ if (!a->exchange) { ++ au_set_dbtop(d, a->dst_btop); ++ err = may_rename_dstdir(d, &a->whlist); ++ au_set_dbtop(d, a->btgt); ++ } else ++ err = may_rename_srcdir(a); ++ } ++ a->dst_h_dentry = au_h_dptr(d, au_dbtop(d)); ++ if (unlikely(err)) ++ goto out; ++ ++ d = a->src_dentry; ++ a->src_h_dentry = au_h_dptr(d, au_dbtop(d)); ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC)) { ++ err = may_rename_srcdir(a); ++ if (unlikely(err)) { ++ au_nhash_wh_free(&a->whlist); ++ a->whlist.nh_num = 0; ++ } ++ } ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * simple tests for rename. ++ * following the checks in vfs, plus the parent-child relationship. ++ */ ++static int au_may_ren(struct au_ren_args *a) ++{ ++ int err, isdir; ++ struct inode *h_inode; ++ ++ if (a->src_btop == a->btgt) { ++ err = au_may_del(a->src_dentry, a->btgt, a->src_h_parent, ++ au_ftest_ren(a->auren_flags, ISDIR_SRC)); ++ if (unlikely(err)) ++ goto out; ++ err = -EINVAL; ++ if (unlikely(a->src_h_dentry == a->h_trap)) ++ goto out; ++ } ++ ++ err = 0; ++ if (a->dst_btop != a->btgt) ++ goto out; ++ ++ err = -ENOTEMPTY; ++ if (unlikely(a->dst_h_dentry == a->h_trap)) ++ goto out; ++ ++ err = -EIO; ++ isdir = !!au_ftest_ren(a->auren_flags, ISDIR_DST); ++ if (d_really_is_negative(a->dst_dentry)) { ++ if (d_is_negative(a->dst_h_dentry)) ++ err = au_may_add(a->dst_dentry, a->btgt, ++ a->dst_h_parent, isdir); ++ } else { ++ if (unlikely(d_is_negative(a->dst_h_dentry))) ++ goto out; ++ h_inode = d_inode(a->dst_h_dentry); ++ if (h_inode->i_nlink) ++ err = au_may_del(a->dst_dentry, a->btgt, ++ a->dst_h_parent, isdir); ++ } ++ ++out: ++ if (unlikely(err == -ENOENT || err == -EEXIST)) ++ err = -EIO; ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * locking order ++ * (VFS) ++ * - src_dir and dir by lock_rename() ++ * - inode if exists ++ * (aufs) ++ * - lock all ++ * + src_dentry and dentry by aufs_read_and_write_lock2() which calls, ++ * + si_read_lock ++ * + di_write_lock2_child() ++ * + di_write_lock_child() ++ * + ii_write_lock_child() ++ * + di_write_lock_child2() ++ * + ii_write_lock_child2() ++ * + src_parent and parent ++ * + di_write_lock_parent() ++ * + ii_write_lock_parent() ++ * + di_write_lock_parent2() ++ * + ii_write_lock_parent2() ++ * + lower src_dir and dir by vfsub_lock_rename() ++ * + verify the every relationships between child and parent. if any ++ * of them failed, unlock all and return -EBUSY. ++ */ ++static void au_ren_unlock(struct au_ren_args *a) ++{ ++ vfsub_unlock_rename(a->src_h_parent, a->src_hdir, ++ a->dst_h_parent, a->dst_hdir); ++ if (au_ftest_ren(a->auren_flags, DIRREN) ++ && a->h_root) ++ au_hn_inode_unlock(a->h_root); ++ if (au_ftest_ren(a->auren_flags, MNT_WRITE)) ++ vfsub_mnt_drop_write(au_br_mnt(a->br)); ++} ++ ++static int au_ren_lock(struct au_ren_args *a) ++{ ++ int err; ++ unsigned int udba; ++ ++ err = 0; ++ a->src_h_parent = au_h_dptr(a->src_parent, a->btgt); ++ a->src_hdir = au_hi(a->src_dir, a->btgt); ++ a->dst_h_parent = au_h_dptr(a->dst_parent, a->btgt); ++ a->dst_hdir = au_hi(a->dst_dir, a->btgt); ++ ++ err = vfsub_mnt_want_write(au_br_mnt(a->br)); ++ if (unlikely(err)) ++ goto out; ++ au_fset_ren(a->auren_flags, MNT_WRITE); ++ if (au_ftest_ren(a->auren_flags, DIRREN)) { ++ struct dentry *root; ++ struct inode *dir; ++ ++ /* ++ * sbinfo is already locked, so this ii_read_lock is ++ * unnecessary. but our debugging feature checks it. ++ */ ++ root = a->src_inode->i_sb->s_root; ++ if (root != a->src_parent && root != a->dst_parent) { ++ dir = d_inode(root); ++ ii_read_lock_parent3(dir); ++ a->h_root = au_hi(dir, a->btgt); ++ ii_read_unlock(dir); ++ au_hn_inode_lock_nested(a->h_root, AuLsc_I_PARENT3); ++ } ++ } ++ a->h_trap = vfsub_lock_rename(a->src_h_parent, a->src_hdir, ++ a->dst_h_parent, a->dst_hdir); ++ udba = au_opt_udba(a->src_dentry->d_sb); ++ if (unlikely(a->src_hdir->hi_inode != d_inode(a->src_h_parent) ++ || a->dst_hdir->hi_inode != d_inode(a->dst_h_parent))) ++ err = au_busy_or_stale(); ++ if (!err && au_dbtop(a->src_dentry) == a->btgt) ++ err = au_h_verify(a->src_h_dentry, udba, ++ d_inode(a->src_h_parent), a->src_h_parent, ++ a->br); ++ if (!err && au_dbtop(a->dst_dentry) == a->btgt) ++ err = au_h_verify(a->dst_h_dentry, udba, ++ d_inode(a->dst_h_parent), a->dst_h_parent, ++ a->br); ++ if (!err) ++ goto out; /* success */ ++ ++ err = au_busy_or_stale(); ++ au_ren_unlock(a); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_ren_refresh_dir(struct au_ren_args *a) ++{ ++ struct inode *dir; ++ ++ dir = a->dst_dir; ++ inode_inc_iversion(dir); ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC)) { ++ /* is this updating defined in POSIX? */ ++ au_cpup_attr_timesizes(a->src_inode); ++ au_cpup_attr_nlink(dir, /*force*/1); ++ } ++ au_dir_ts(dir, a->btgt); ++ ++ if (a->exchange) { ++ dir = a->src_dir; ++ inode_inc_iversion(dir); ++ if (au_ftest_ren(a->auren_flags, ISDIR_DST)) { ++ /* is this updating defined in POSIX? */ ++ au_cpup_attr_timesizes(a->dst_inode); ++ au_cpup_attr_nlink(dir, /*force*/1); ++ } ++ au_dir_ts(dir, a->btgt); ++ } ++ ++ if (au_ftest_ren(a->auren_flags, ISSAMEDIR)) ++ return; ++ ++ dir = a->src_dir; ++ inode_inc_iversion(dir); ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC)) ++ au_cpup_attr_nlink(dir, /*force*/1); ++ au_dir_ts(dir, a->btgt); ++} ++ ++static void au_ren_refresh(struct au_ren_args *a) ++{ ++ aufs_bindex_t bbot, bindex; ++ struct dentry *d, *h_d; ++ struct inode *i, *h_i; ++ struct super_block *sb; ++ ++ d = a->dst_dentry; ++ d_drop(d); ++ if (a->h_dst) ++ /* already dget-ed by au_ren_or_cpup() */ ++ au_set_h_dptr(d, a->btgt, a->h_dst); ++ ++ i = a->dst_inode; ++ if (i) { ++ if (!a->exchange) { ++ if (!au_ftest_ren(a->auren_flags, ISDIR_DST)) ++ vfsub_drop_nlink(i); ++ else { ++ vfsub_dead_dir(i); ++ au_cpup_attr_timesizes(i); ++ } ++ au_update_dbrange(d, /*do_put_zero*/1); ++ } else ++ au_cpup_attr_nlink(i, /*force*/1); ++ } else { ++ bbot = a->btgt; ++ for (bindex = au_dbtop(d); bindex < bbot; bindex++) ++ au_set_h_dptr(d, bindex, NULL); ++ bbot = au_dbbot(d); ++ for (bindex = a->btgt + 1; bindex <= bbot; bindex++) ++ au_set_h_dptr(d, bindex, NULL); ++ au_update_dbrange(d, /*do_put_zero*/0); ++ } ++ ++ if (a->exchange ++ || au_ftest_ren(a->auren_flags, DIRREN)) { ++ d_drop(a->src_dentry); ++ if (au_ftest_ren(a->auren_flags, DIRREN)) ++ au_set_dbwh(a->src_dentry, -1); ++ return; ++ } ++ ++ d = a->src_dentry; ++ au_set_dbwh(d, -1); ++ bbot = au_dbbot(d); ++ for (bindex = a->btgt + 1; bindex <= bbot; bindex++) { ++ h_d = au_h_dptr(d, bindex); ++ if (h_d) ++ au_set_h_dptr(d, bindex, NULL); ++ } ++ au_set_dbbot(d, a->btgt); ++ ++ sb = d->d_sb; ++ i = a->src_inode; ++ if (au_opt_test(au_mntflags(sb), PLINK) && au_plink_test(i)) ++ return; /* success */ ++ ++ bbot = au_ibbot(i); ++ for (bindex = a->btgt + 1; bindex <= bbot; bindex++) { ++ h_i = au_h_iptr(i, bindex); ++ if (h_i) { ++ au_xino_write(sb, bindex, h_i->i_ino, /*ino*/0); ++ /* ignore this error */ ++ au_set_h_iptr(i, bindex, NULL, 0); ++ } ++ } ++ au_set_ibbot(i, a->btgt); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* mainly for link(2) and rename(2) */ ++int au_wbr(struct dentry *dentry, aufs_bindex_t btgt) ++{ ++ aufs_bindex_t bdiropq, bwh; ++ struct dentry *parent; ++ struct au_branch *br; ++ ++ parent = dentry->d_parent; ++ IMustLock(d_inode(parent)); /* dir is locked */ ++ ++ bdiropq = au_dbdiropq(parent); ++ bwh = au_dbwh(dentry); ++ br = au_sbr(dentry->d_sb, btgt); ++ if (au_br_rdonly(br) ++ || (0 <= bdiropq && bdiropq < btgt) ++ || (0 <= bwh && bwh < btgt)) ++ btgt = -1; ++ ++ AuDbg("btgt %d\n", btgt); ++ return btgt; ++} ++ ++/* sets src_btop, dst_btop and btgt */ ++static int au_ren_wbr(struct au_ren_args *a) ++{ ++ int err; ++ struct au_wr_dir_args wr_dir_args = { ++ /* .force_btgt = -1, */ ++ .flags = AuWrDir_ADD_ENTRY ++ }; ++ ++ a->src_btop = au_dbtop(a->src_dentry); ++ a->dst_btop = au_dbtop(a->dst_dentry); ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC) ++ || au_ftest_ren(a->auren_flags, ISDIR_DST)) ++ au_fset_wrdir(wr_dir_args.flags, ISDIR); ++ wr_dir_args.force_btgt = a->src_btop; ++ if (a->dst_inode && a->dst_btop < a->src_btop) ++ wr_dir_args.force_btgt = a->dst_btop; ++ wr_dir_args.force_btgt = au_wbr(a->dst_dentry, wr_dir_args.force_btgt); ++ err = au_wr_dir(a->dst_dentry, a->src_dentry, &wr_dir_args); ++ a->btgt = err; ++ if (a->exchange) ++ au_update_dbtop(a->dst_dentry); ++ ++ return err; ++} ++ ++static void au_ren_dt(struct au_ren_args *a) ++{ ++ a->h_path.dentry = a->src_h_parent; ++ au_dtime_store(a->src_dt + AuPARENT, a->src_parent, &a->h_path); ++ if (!au_ftest_ren(a->auren_flags, ISSAMEDIR)) { ++ a->h_path.dentry = a->dst_h_parent; ++ au_dtime_store(a->dst_dt + AuPARENT, a->dst_parent, &a->h_path); ++ } ++ ++ au_fclr_ren(a->auren_flags, DT_DSTDIR); ++ if (!au_ftest_ren(a->auren_flags, ISDIR_SRC) ++ && !a->exchange) ++ return; ++ ++ a->h_path.dentry = a->src_h_dentry; ++ au_dtime_store(a->src_dt + AuCHILD, a->src_dentry, &a->h_path); ++ if (d_is_positive(a->dst_h_dentry)) { ++ au_fset_ren(a->auren_flags, DT_DSTDIR); ++ a->h_path.dentry = a->dst_h_dentry; ++ au_dtime_store(a->dst_dt + AuCHILD, a->dst_dentry, &a->h_path); ++ } ++} ++ ++static void au_ren_rev_dt(int err, struct au_ren_args *a) ++{ ++ struct dentry *h_d; ++ struct inode *h_inode; ++ ++ au_dtime_revert(a->src_dt + AuPARENT); ++ if (!au_ftest_ren(a->auren_flags, ISSAMEDIR)) ++ au_dtime_revert(a->dst_dt + AuPARENT); ++ ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC) && err != -EIO) { ++ h_d = a->src_dt[AuCHILD].dt_h_path.dentry; ++ h_inode = d_inode(h_d); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ au_dtime_revert(a->src_dt + AuCHILD); ++ inode_unlock(h_inode); ++ ++ if (au_ftest_ren(a->auren_flags, DT_DSTDIR)) { ++ h_d = a->dst_dt[AuCHILD].dt_h_path.dentry; ++ h_inode = d_inode(h_d); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ au_dtime_revert(a->dst_dt + AuCHILD); ++ inode_unlock(h_inode); ++ } ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int aufs_rename(struct user_namespace *userns, ++ struct inode *_src_dir, struct dentry *_src_dentry, ++ struct inode *_dst_dir, struct dentry *_dst_dentry, ++ unsigned int _flags) ++{ ++ int err, lock_flags; ++ void *rev; ++ /* reduce stack space */ ++ struct au_ren_args *a; ++ struct au_pin pin; ++ ++ AuDbg("%pd, %pd, 0x%x\n", _src_dentry, _dst_dentry, _flags); ++ IMustLock(_src_dir); ++ IMustLock(_dst_dir); ++ ++ err = -EINVAL; ++ if (unlikely(_flags & RENAME_WHITEOUT)) ++ goto out; ++ ++ err = -ENOMEM; ++ BUILD_BUG_ON(sizeof(*a) > PAGE_SIZE); ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ a->flags = _flags; ++ BUILD_BUG_ON(sizeof(a->exchange) == sizeof(u8) ++ && RENAME_EXCHANGE > U8_MAX); ++ a->exchange = _flags & RENAME_EXCHANGE; ++ a->src_dir = _src_dir; ++ a->src_dentry = _src_dentry; ++ a->src_inode = NULL; ++ if (d_really_is_positive(a->src_dentry)) ++ a->src_inode = d_inode(a->src_dentry); ++ a->src_parent = a->src_dentry->d_parent; /* dir inode is locked */ ++ a->dst_dir = _dst_dir; ++ a->dst_dentry = _dst_dentry; ++ a->dst_inode = NULL; ++ if (d_really_is_positive(a->dst_dentry)) ++ a->dst_inode = d_inode(a->dst_dentry); ++ a->dst_parent = a->dst_dentry->d_parent; /* dir inode is locked */ ++ if (a->dst_inode) { ++ /* ++ * if EXCHANGE && src is non-dir && dst is dir, ++ * dst is not locked. ++ */ ++ /* IMustLock(a->dst_inode); */ ++ au_igrab(a->dst_inode); ++ } ++ ++ err = -ENOTDIR; ++ lock_flags = AuLock_FLUSH | AuLock_NOPLM | AuLock_GEN; ++ if (d_is_dir(a->src_dentry)) { ++ au_fset_ren(a->auren_flags, ISDIR_SRC); ++ if (unlikely(!a->exchange ++ && d_really_is_positive(a->dst_dentry) ++ && !d_is_dir(a->dst_dentry))) ++ goto out_free; ++ lock_flags |= AuLock_DIRS; ++ } ++ if (a->dst_inode && d_is_dir(a->dst_dentry)) { ++ au_fset_ren(a->auren_flags, ISDIR_DST); ++ if (unlikely(!a->exchange ++ && d_really_is_positive(a->src_dentry) ++ && !d_is_dir(a->src_dentry))) ++ goto out_free; ++ lock_flags |= AuLock_DIRS; ++ } ++ err = aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry, ++ lock_flags); ++ if (unlikely(err)) ++ goto out_free; ++ ++ err = au_d_hashed_positive(a->src_dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ err = -ENOENT; ++ if (a->dst_inode) { ++ /* ++ * If it is a dir, VFS unhash it before this ++ * function. It means we cannot rely upon d_unhashed(). ++ */ ++ if (unlikely(!a->dst_inode->i_nlink)) ++ goto out_unlock; ++ if (!au_ftest_ren(a->auren_flags, ISDIR_DST)) { ++ err = au_d_hashed_positive(a->dst_dentry); ++ if (unlikely(err && !a->exchange)) ++ goto out_unlock; ++ } else if (unlikely(IS_DEADDIR(a->dst_inode))) ++ goto out_unlock; ++ } else if (unlikely(d_unhashed(a->dst_dentry))) ++ goto out_unlock; ++ ++ /* ++ * is it possible? ++ * yes, it happened (in linux-3.3-rcN) but I don't know why. ++ * there may exist a problem somewhere else. ++ */ ++ err = -EINVAL; ++ if (unlikely(d_inode(a->dst_parent) == d_inode(a->src_dentry))) ++ goto out_unlock; ++ ++ au_fset_ren(a->auren_flags, ISSAMEDIR); /* temporary */ ++ di_write_lock_parent(a->dst_parent); ++ ++ /* which branch we process */ ++ err = au_ren_wbr(a); ++ if (unlikely(err < 0)) ++ goto out_parent; ++ a->br = au_sbr(a->dst_dentry->d_sb, a->btgt); ++ a->h_path.mnt = au_br_mnt(a->br); ++ ++ /* are they available to be renamed */ ++ err = au_ren_may_dir(a); ++ if (unlikely(err)) ++ goto out_children; ++ ++ /* prepare the writable parent dir on the same branch */ ++ if (a->dst_btop == a->btgt) { ++ au_fset_ren(a->auren_flags, WHDST); ++ } else { ++ err = au_cpup_dirs(a->dst_dentry, a->btgt); ++ if (unlikely(err)) ++ goto out_children; ++ } ++ ++ err = 0; ++ if (!a->exchange) { ++ if (a->src_dir != a->dst_dir) { ++ /* ++ * this temporary unlock is safe, ++ * because both dir->i_mutex are locked. ++ */ ++ di_write_unlock(a->dst_parent); ++ di_write_lock_parent(a->src_parent); ++ err = au_wr_dir_need_wh(a->src_dentry, ++ au_ftest_ren(a->auren_flags, ++ ISDIR_SRC), ++ &a->btgt); ++ di_write_unlock(a->src_parent); ++ di_write_lock2_parent(a->src_parent, a->dst_parent, ++ /*isdir*/1); ++ au_fclr_ren(a->auren_flags, ISSAMEDIR); ++ } else ++ err = au_wr_dir_need_wh(a->src_dentry, ++ au_ftest_ren(a->auren_flags, ++ ISDIR_SRC), ++ &a->btgt); ++ } ++ if (unlikely(err < 0)) ++ goto out_children; ++ if (err) ++ au_fset_ren(a->auren_flags, WHSRC); ++ ++ /* cpup src */ ++ if (a->src_btop != a->btgt) { ++ err = au_pin(&pin, a->src_dentry, a->btgt, ++ au_opt_udba(a->src_dentry->d_sb), ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (!err) { ++ struct au_cp_generic cpg = { ++ .dentry = a->src_dentry, ++ .bdst = a->btgt, ++ .bsrc = a->src_btop, ++ .len = -1, ++ .pin = &pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ AuDebugOn(au_dbtop(a->src_dentry) != a->src_btop); ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&pin); ++ } ++ if (unlikely(err)) ++ goto out_children; ++ a->src_btop = a->btgt; ++ a->src_h_dentry = au_h_dptr(a->src_dentry, a->btgt); ++ if (!a->exchange) ++ au_fset_ren(a->auren_flags, WHSRC); ++ } ++ ++ /* cpup dst */ ++ if (a->exchange && a->dst_inode ++ && a->dst_btop != a->btgt) { ++ err = au_pin(&pin, a->dst_dentry, a->btgt, ++ au_opt_udba(a->dst_dentry->d_sb), ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (!err) { ++ struct au_cp_generic cpg = { ++ .dentry = a->dst_dentry, ++ .bdst = a->btgt, ++ .bsrc = a->dst_btop, ++ .len = -1, ++ .pin = &pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&pin); ++ } ++ if (unlikely(err)) ++ goto out_children; ++ a->dst_btop = a->btgt; ++ a->dst_h_dentry = au_h_dptr(a->dst_dentry, a->btgt); ++ } ++ ++ /* lock them all */ ++ err = au_ren_lock(a); ++ if (unlikely(err)) ++ /* leave the copied-up one */ ++ goto out_children; ++ ++ if (!a->exchange) { ++ if (!au_opt_test(au_mntflags(a->dst_dir->i_sb), UDBA_NONE)) ++ err = au_may_ren(a); ++ else if (unlikely(a->dst_dentry->d_name.len > AUFS_MAX_NAMELEN)) ++ err = -ENAMETOOLONG; ++ if (unlikely(err)) ++ goto out_hdir; ++ } ++ ++ /* store timestamps to be revertible */ ++ au_ren_dt(a); ++ ++ /* store dirren info */ ++ if (au_ftest_ren(a->auren_flags, DIRREN)) { ++ err = au_dr_rename(a->src_dentry, a->btgt, ++ &a->dst_dentry->d_name, &rev); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out_dt; ++ } ++ ++ /* here we go */ ++ err = do_rename(a); ++ if (unlikely(err)) ++ goto out_dirren; ++ ++ if (au_ftest_ren(a->auren_flags, DIRREN)) ++ au_dr_rename_fin(a->src_dentry, a->btgt, rev); ++ ++ /* update dir attributes */ ++ au_ren_refresh_dir(a); ++ ++ /* dput/iput all lower dentries */ ++ au_ren_refresh(a); ++ ++ goto out_hdir; /* success */ ++ ++out_dirren: ++ if (au_ftest_ren(a->auren_flags, DIRREN)) ++ au_dr_rename_rev(a->src_dentry, a->btgt, rev); ++out_dt: ++ au_ren_rev_dt(err, a); ++out_hdir: ++ au_ren_unlock(a); ++out_children: ++ au_nhash_wh_free(&a->whlist); ++ if (err && a->dst_inode && a->dst_btop != a->btgt) { ++ AuDbg("btop %d, btgt %d\n", a->dst_btop, a->btgt); ++ au_set_h_dptr(a->dst_dentry, a->btgt, NULL); ++ au_set_dbtop(a->dst_dentry, a->dst_btop); ++ } ++out_parent: ++ if (!err) { ++ if (d_unhashed(a->src_dentry)) ++ au_fset_ren(a->auren_flags, DROPPED_SRC); ++ if (d_unhashed(a->dst_dentry)) ++ au_fset_ren(a->auren_flags, DROPPED_DST); ++ if (!a->exchange) ++ d_move(a->src_dentry, a->dst_dentry); ++ else { ++ d_exchange(a->src_dentry, a->dst_dentry); ++ if (au_ftest_ren(a->auren_flags, DROPPED_DST)) ++ d_drop(a->dst_dentry); ++ } ++ if (au_ftest_ren(a->auren_flags, DROPPED_SRC)) ++ d_drop(a->src_dentry); ++ } else { ++ au_update_dbtop(a->dst_dentry); ++ if (!a->dst_inode) ++ d_drop(a->dst_dentry); ++ } ++ if (au_ftest_ren(a->auren_flags, ISSAMEDIR)) ++ di_write_unlock(a->dst_parent); ++ else ++ di_write_unlock2(a->src_parent, a->dst_parent); ++out_unlock: ++ aufs_read_and_write_unlock2(a->dst_dentry, a->src_dentry); ++out_free: ++ iput(a->dst_inode); ++ if (a->thargs) ++ au_whtmp_rmdir_free(a->thargs); ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} +diff -Naur null/fs/aufs/Kconfig linux-5.15.36/fs/aufs/Kconfig +--- /dev/null ++++ linux-5.15.36/fs/aufs/Kconfig 2022-05-10 16:51:39.866744220 +0300 +@@ -0,0 +1,199 @@ ++# SPDX-License-Identifier: GPL-2.0 ++config AUFS_FS ++ tristate "Aufs (Advanced multi layered unification filesystem) support" ++ help ++ Aufs is a stackable unification filesystem such as Unionfs, ++ which unifies several directories and provides a merged single ++ directory. ++ In the early days, aufs was entirely re-designed and ++ re-implemented Unionfs Version 1.x series. Introducing many ++ original ideas, approaches and improvements, it becomes totally ++ different from Unionfs while keeping the basic features. ++ ++if AUFS_FS ++choice ++ prompt "Maximum number of branches" ++ default AUFS_BRANCH_MAX_127 ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++config AUFS_BRANCH_MAX_127 ++ bool "127" ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++config AUFS_BRANCH_MAX_511 ++ bool "511" ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++config AUFS_BRANCH_MAX_1023 ++ bool "1023" ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++config AUFS_BRANCH_MAX_32767 ++ bool "32767" ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++endchoice ++ ++config AUFS_SBILIST ++ bool ++ depends on AUFS_MAGIC_SYSRQ || PROC_FS ++ default y ++ help ++ Automatic configuration for internal use. ++ When aufs supports Magic SysRq or /proc, enabled automatically. ++ ++config AUFS_HNOTIFY ++ bool "Detect direct branch access (bypassing aufs)" ++ help ++ If you want to modify files on branches directly, eg. bypassing aufs, ++ and want aufs to detect the changes of them fully, then enable this ++ option and use 'udba=notify' mount option. ++ Currently there is only one available configuration, "fsnotify". ++ It will have a negative impact to the performance. ++ See detail in aufs.5. ++ ++choice ++ prompt "method" if AUFS_HNOTIFY ++ default AUFS_HFSNOTIFY ++config AUFS_HFSNOTIFY ++ bool "fsnotify" ++ select FSNOTIFY ++endchoice ++ ++config AUFS_EXPORT ++ bool "NFS-exportable aufs" ++ depends on EXPORTFS ++ help ++ If you want to export your mounted aufs via NFS, then enable this ++ option. There are several requirements for this configuration. ++ See detail in aufs.5. ++ ++config AUFS_INO_T_64 ++ bool ++ depends on AUFS_EXPORT ++ depends on 64BIT && !(ALPHA || S390) ++ default y ++ help ++ Automatic configuration for internal use. ++ /* typedef unsigned long/int __kernel_ino_t */ ++ /* alpha and s390x are int */ ++ ++config AUFS_XATTR ++ bool "support for XATTR/EA (including Security Labels)" ++ help ++ If your branch fs supports XATTR/EA and you want to make them ++ available in aufs too, then enable this opsion and specify the ++ branch attributes for EA. ++ See detail in aufs.5. ++ ++config AUFS_FHSM ++ bool "File-based Hierarchical Storage Management" ++ help ++ Hierarchical Storage Management (or HSM) is a well-known feature ++ in the storage world. Aufs provides this feature as file-based. ++ with multiple branches. ++ These multiple branches are prioritized, ie. the topmost one ++ should be the fastest drive and be used heavily. ++ ++config AUFS_RDU ++ bool "Readdir in userspace" ++ help ++ Aufs has two methods to provide a merged view for a directory, ++ by a user-space library and by kernel-space natively. The latter ++ is always enabled but sometimes large and slow. ++ If you enable this option, install the library in aufs2-util ++ package, and set some environment variables for your readdir(3), ++ then the work will be handled in user-space which generally ++ shows better performance in most cases. ++ See detail in aufs.5. ++ ++config AUFS_DIRREN ++ bool "Workaround for rename(2)-ing a directory" ++ help ++ By default, aufs returns EXDEV error in renameing a dir who has ++ his child on the lower branch, since it is a bad idea to issue ++ rename(2) internally for every lower branch. But user may not ++ accept this behaviour. So here is a workaround to allow such ++ rename(2) and store some extra infromation on the writable ++ branch. Obviously this costs high (and I don't like it). ++ To use this feature, you need to enable this configuration AND ++ to specify the mount option `dirren.' ++ See details in aufs.5 and the design documents. ++ ++config AUFS_SHWH ++ bool "Show whiteouts" ++ help ++ If you want to make the whiteouts in aufs visible, then enable ++ this option and specify 'shwh' mount option. Although it may ++ sounds like philosophy or something, but in technically it ++ simply shows the name of whiteout with keeping its behaviour. ++ ++config AUFS_BR_RAMFS ++ bool "Ramfs (initramfs/rootfs) as an aufs branch" ++ help ++ If you want to use ramfs as an aufs branch fs, then enable this ++ option. Generally tmpfs is recommended. ++ Aufs prohibited them to be a branch fs by default, because ++ initramfs becomes unusable after switch_root or something ++ generally. If you sets initramfs as an aufs branch and boot your ++ system by switch_root, you will meet a problem easily since the ++ files in initramfs may be inaccessible. ++ Unless you are going to use ramfs as an aufs branch fs without ++ switch_root or something, leave it N. ++ ++config AUFS_BR_FUSE ++ bool "Fuse fs as an aufs branch" ++ depends on FUSE_FS ++ select AUFS_POLL ++ help ++ If you want to use fuse-based userspace filesystem as an aufs ++ branch fs, then enable this option. ++ It implements the internal poll(2) operation which is ++ implemented by fuse only (curretnly). ++ ++config AUFS_POLL ++ bool ++ help ++ Automatic configuration for internal use. ++ ++config AUFS_BR_HFSPLUS ++ bool "Hfsplus as an aufs branch" ++ depends on HFSPLUS_FS ++ default y ++ help ++ If you want to use hfsplus fs as an aufs branch fs, then enable ++ this option. This option introduces a small overhead at ++ copying-up a file on hfsplus. ++ ++config AUFS_BDEV_LOOP ++ bool ++ depends on BLK_DEV_LOOP ++ default y ++ help ++ Automatic configuration for internal use. ++ Convert =[ym] into =y. ++ ++config AUFS_DEBUG ++ bool "Debug aufs" ++ help ++ Enable this to compile aufs internal debug code. ++ It will have a negative impact to the performance. ++ ++config AUFS_MAGIC_SYSRQ ++ bool ++ depends on AUFS_DEBUG && MAGIC_SYSRQ ++ default y ++ help ++ Automatic configuration for internal use. ++ When aufs supports Magic SysRq, enabled automatically. ++endif +diff -Naur null/fs/aufs/lcnt.h linux-5.15.36/fs/aufs/lcnt.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/lcnt.h 2022-05-10 16:51:39.874744219 +0300 +@@ -0,0 +1,186 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2018-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * simple long counter wrapper ++ */ ++ ++#ifndef __AUFS_LCNT_H__ ++#define __AUFS_LCNT_H__ ++ ++#ifdef __KERNEL__ ++ ++#include "debug.h" ++ ++#define AuLCntATOMIC 1 ++#define AuLCntPCPUCNT 2 ++/* ++ * why does percpu_refcount require extra synchronize_rcu()s in ++ * au_br_do_free() ++ */ ++#define AuLCntPCPUREF 3 ++ ++/* #define AuLCntChosen AuLCntATOMIC */ ++#define AuLCntChosen AuLCntPCPUCNT ++/* #define AuLCntChosen AuLCntPCPUREF */ ++ ++#if AuLCntChosen == AuLCntATOMIC ++#include ++ ++typedef atomic_long_t au_lcnt_t; ++ ++static inline int au_lcnt_init(au_lcnt_t *cnt, void *release __maybe_unused) ++{ ++ atomic_long_set(cnt, 0); ++ return 0; ++} ++ ++static inline void au_lcnt_wait_for_fin(au_lcnt_t *cnt __maybe_unused) ++{ ++ /* empty */ ++} ++ ++static inline void au_lcnt_fin(au_lcnt_t *cnt __maybe_unused, ++ int do_sync __maybe_unused) ++{ ++ /* empty */ ++} ++ ++static inline void au_lcnt_inc(au_lcnt_t *cnt) ++{ ++ atomic_long_inc(cnt); ++} ++ ++static inline void au_lcnt_dec(au_lcnt_t *cnt) ++{ ++ atomic_long_dec(cnt); ++} ++ ++static inline long au_lcnt_read(au_lcnt_t *cnt, int do_rev __maybe_unused) ++{ ++ return atomic_long_read(cnt); ++} ++#endif ++ ++#if AuLCntChosen == AuLCntPCPUCNT ++#include ++ ++typedef struct percpu_counter au_lcnt_t; ++ ++static inline int au_lcnt_init(au_lcnt_t *cnt, void *release __maybe_unused) ++{ ++ return percpu_counter_init(cnt, 0, GFP_NOFS); ++} ++ ++static inline void au_lcnt_wait_for_fin(au_lcnt_t *cnt __maybe_unused) ++{ ++ /* empty */ ++} ++ ++static inline void au_lcnt_fin(au_lcnt_t *cnt, int do_sync __maybe_unused) ++{ ++ percpu_counter_destroy(cnt); ++} ++ ++static inline void au_lcnt_inc(au_lcnt_t *cnt) ++{ ++ percpu_counter_inc(cnt); ++} ++ ++static inline void au_lcnt_dec(au_lcnt_t *cnt) ++{ ++ percpu_counter_dec(cnt); ++} ++ ++static inline long au_lcnt_read(au_lcnt_t *cnt, int do_rev __maybe_unused) ++{ ++ s64 n; ++ ++ n = percpu_counter_sum(cnt); ++ BUG_ON(n < 0); ++ if (LONG_MAX != LLONG_MAX ++ && n > LONG_MAX) ++ AuWarn1("%s\n", "wrap-around"); ++ ++ return n; ++} ++#endif ++ ++#if AuLCntChosen == AuLCntPCPUREF ++#include ++ ++typedef struct percpu_ref au_lcnt_t; ++ ++static inline int au_lcnt_init(au_lcnt_t *cnt, percpu_ref_func_t *release) ++{ ++ if (!release) ++ release = percpu_ref_exit; ++ return percpu_ref_init(cnt, release, /*percpu mode*/0, GFP_NOFS); ++} ++ ++static inline void au_lcnt_wait_for_fin(au_lcnt_t *cnt __maybe_unused) ++{ ++ synchronize_rcu(); ++} ++ ++static inline void au_lcnt_fin(au_lcnt_t *cnt, int do_sync) ++{ ++ percpu_ref_kill(cnt); ++ if (do_sync) ++ au_lcnt_wait_for_fin(cnt); ++} ++ ++static inline void au_lcnt_inc(au_lcnt_t *cnt) ++{ ++ percpu_ref_get(cnt); ++} ++ ++static inline void au_lcnt_dec(au_lcnt_t *cnt) ++{ ++ percpu_ref_put(cnt); ++} ++ ++/* ++ * avoid calling this func as possible. ++ */ ++static inline long au_lcnt_read(au_lcnt_t *cnt, int do_rev) ++{ ++ long l; ++ ++ percpu_ref_switch_to_atomic_sync(cnt); ++ l = atomic_long_read(&cnt->count); ++ if (do_rev) ++ percpu_ref_switch_to_percpu(cnt); ++ ++ /* percpu_ref is initialized by 1 instead of 0 */ ++ return l - 1; ++} ++#endif ++ ++#ifdef CONFIG_AUFS_DEBUG ++#define AuLCntZero(val) do { \ ++ long l = val; \ ++ if (l) \ ++ AuDbg("%s = %ld\n", #val, l); \ ++} while (0) ++#else ++#define AuLCntZero(val) do {} while (0) ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_LCNT_H__ */ +diff -Naur null/fs/aufs/loop.c linux-5.15.36/fs/aufs/loop.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/loop.c 2022-05-10 16:51:39.874744219 +0300 +@@ -0,0 +1,148 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * support for loopback block device as a branch ++ */ ++ ++#include "aufs.h" ++ ++/* added into drivers/block/loop.c */ ++static struct file *(*backing_file_func)(struct super_block *sb); ++ ++/* ++ * test if two lower dentries have overlapping branches. ++ */ ++int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_adding) ++{ ++ struct super_block *h_sb; ++ struct file *backing_file; ++ ++ if (unlikely(!backing_file_func)) { ++ /* don't load "loop" module here */ ++ backing_file_func = symbol_get(loop_backing_file); ++ if (unlikely(!backing_file_func)) ++ /* "loop" module is not loaded */ ++ return 0; ++ } ++ ++ h_sb = h_adding->d_sb; ++ backing_file = backing_file_func(h_sb); ++ if (!backing_file) ++ return 0; ++ ++ h_adding = backing_file->f_path.dentry; ++ /* ++ * h_adding can be local NFS. ++ * in this case aufs cannot detect the loop. ++ */ ++ if (unlikely(h_adding->d_sb == sb)) ++ return 1; ++ return !!au_test_subdir(h_adding, sb->s_root); ++} ++ ++/* true if a kernel thread named 'loop[0-9].*' accesses a file */ ++int au_test_loopback_kthread(void) ++{ ++ int ret; ++ struct task_struct *tsk = current; ++ char c, comm[sizeof(tsk->comm)]; ++ ++ ret = 0; ++ if (tsk->flags & PF_KTHREAD) { ++ get_task_comm(comm, tsk); ++ c = comm[4]; ++ ret = ('0' <= c && c <= '9' ++ && !strncmp(comm, "loop", 4)); ++ } ++ ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define au_warn_loopback_step 16 ++static int au_warn_loopback_nelem = au_warn_loopback_step; ++static unsigned long *au_warn_loopback_array; ++ ++void au_warn_loopback(struct super_block *h_sb) ++{ ++ int i, new_nelem; ++ unsigned long *a, magic; ++ static DEFINE_SPINLOCK(spin); ++ ++ magic = h_sb->s_magic; ++ spin_lock(&spin); ++ a = au_warn_loopback_array; ++ for (i = 0; i < au_warn_loopback_nelem && *a; i++) ++ if (a[i] == magic) { ++ spin_unlock(&spin); ++ return; ++ } ++ ++ /* h_sb is new to us, print it */ ++ if (i < au_warn_loopback_nelem) { ++ a[i] = magic; ++ goto pr; ++ } ++ ++ /* expand the array */ ++ new_nelem = au_warn_loopback_nelem + au_warn_loopback_step; ++ a = au_kzrealloc(au_warn_loopback_array, ++ au_warn_loopback_nelem * sizeof(unsigned long), ++ new_nelem * sizeof(unsigned long), GFP_ATOMIC, ++ /*may_shrink*/0); ++ if (a) { ++ au_warn_loopback_nelem = new_nelem; ++ au_warn_loopback_array = a; ++ a[i] = magic; ++ goto pr; ++ } ++ ++ spin_unlock(&spin); ++ AuWarn1("realloc failed, ignored\n"); ++ return; ++ ++pr: ++ spin_unlock(&spin); ++ pr_warn("you may want to try another patch for loopback file " ++ "on %s(0x%lx) branch\n", au_sbtype(h_sb), magic); ++} ++ ++int au_loopback_init(void) ++{ ++ int err; ++ struct super_block *sb __maybe_unused; ++ ++ BUILD_BUG_ON(sizeof(sb->s_magic) != sizeof(*au_warn_loopback_array)); ++ ++ err = 0; ++ au_warn_loopback_array = kcalloc(au_warn_loopback_step, ++ sizeof(unsigned long), GFP_NOFS); ++ if (unlikely(!au_warn_loopback_array)) ++ err = -ENOMEM; ++ ++ return err; ++} ++ ++void au_loopback_fin(void) ++{ ++ if (backing_file_func) ++ symbol_put(loop_backing_file); ++ au_kfree_try_rcu(au_warn_loopback_array); ++} +diff -Naur null/fs/aufs/loop.h linux-5.15.36/fs/aufs/loop.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/loop.h 2022-05-10 16:51:39.874744219 +0300 +@@ -0,0 +1,55 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * support for loopback mount as a branch ++ */ ++ ++#ifndef __AUFS_LOOP_H__ ++#define __AUFS_LOOP_H__ ++ ++#ifdef __KERNEL__ ++ ++struct dentry; ++struct super_block; ++ ++#ifdef CONFIG_AUFS_BDEV_LOOP ++/* drivers/block/loop.c */ ++struct file *loop_backing_file(struct super_block *sb); ++ ++/* loop.c */ ++int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_adding); ++int au_test_loopback_kthread(void); ++void au_warn_loopback(struct super_block *h_sb); ++ ++int au_loopback_init(void); ++void au_loopback_fin(void); ++#else ++AuStub(struct file *, loop_backing_file, return NULL, struct super_block *sb) ++ ++AuStubInt0(au_test_loopback_overlap, struct super_block *sb, ++ struct dentry *h_adding) ++AuStubInt0(au_test_loopback_kthread, void) ++AuStubVoid(au_warn_loopback, struct super_block *h_sb) ++ ++AuStubInt0(au_loopback_init, void) ++AuStubVoid(au_loopback_fin, void) ++#endif /* BLK_DEV_LOOP */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_LOOP_H__ */ +diff -Naur null/fs/aufs/magic.mk linux-5.15.36/fs/aufs/magic.mk +--- /dev/null ++++ linux-5.15.36/fs/aufs/magic.mk 2022-05-10 16:51:39.874744219 +0300 +@@ -0,0 +1,31 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++# defined in ${srctree}/fs/fuse/inode.c ++# tristate ++ifdef CONFIG_FUSE_FS ++ccflags-y += -DFUSE_SUPER_MAGIC=0x65735546 ++endif ++ ++# defined in ${srctree}/fs/xfs/xfs_sb.h ++# tristate ++ifdef CONFIG_XFS_FS ++ccflags-y += -DXFS_SB_MAGIC=0x58465342 ++endif ++ ++# defined in ${srctree}/fs/configfs/mount.c ++# tristate ++ifdef CONFIG_CONFIGFS_FS ++ccflags-y += -DCONFIGFS_MAGIC=0x62656570 ++endif ++ ++# defined in ${srctree}/fs/ubifs/ubifs.h ++# tristate ++ifdef CONFIG_UBIFS_FS ++ccflags-y += -DUBIFS_SUPER_MAGIC=0x24051905 ++endif ++ ++# defined in ${srctree}/fs/hfsplus/hfsplus_raw.h ++# tristate ++ifdef CONFIG_HFSPLUS_FS ++ccflags-y += -DHFSPLUS_SUPER_MAGIC=0x482b ++endif +diff -Naur null/fs/aufs/Makefile linux-5.15.36/fs/aufs/Makefile +--- /dev/null ++++ linux-5.15.36/fs/aufs/Makefile 2022-05-10 16:51:39.866744220 +0300 +@@ -0,0 +1,46 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++include ${src}/magic.mk ++ifeq (${CONFIG_AUFS_FS},m) ++include ${src}/conf.mk ++endif ++-include ${src}/priv_def.mk ++ ++# cf. include/linux/kernel.h ++# enable pr_debug ++ccflags-y += -DDEBUG ++# sparse requires the full pathname ++ifdef M ++ccflags-y += -include ${M}/../../include/uapi/linux/aufs_type.h ++else ++ccflags-y += -include ${srctree}/include/uapi/linux/aufs_type.h ++endif ++ ++obj-$(CONFIG_AUFS_FS) += aufs.o ++aufs-y := module.o sbinfo.o super.o branch.o xino.o sysaufs.o opts.o fsctx.o \ ++ wkq.o vfsub.o dcsub.o \ ++ cpup.o whout.o wbr_policy.o \ ++ dinfo.o dentry.o \ ++ dynop.o \ ++ finfo.o file.o f_op.o \ ++ dir.o vdir.o \ ++ iinfo.o inode.o i_op.o i_op_add.o i_op_del.o i_op_ren.o \ ++ mvdown.o ioctl.o ++ ++# all are boolean ++aufs-$(CONFIG_PROC_FS) += procfs.o plink.o ++aufs-$(CONFIG_SYSFS) += sysfs.o ++aufs-$(CONFIG_DEBUG_FS) += dbgaufs.o ++aufs-$(CONFIG_AUFS_BDEV_LOOP) += loop.o ++aufs-$(CONFIG_AUFS_HNOTIFY) += hnotify.o ++aufs-$(CONFIG_AUFS_HFSNOTIFY) += hfsnotify.o ++aufs-$(CONFIG_AUFS_EXPORT) += export.o ++aufs-$(CONFIG_AUFS_XATTR) += xattr.o ++aufs-$(CONFIG_FS_POSIX_ACL) += posix_acl.o ++aufs-$(CONFIG_AUFS_DIRREN) += dirren.o ++aufs-$(CONFIG_AUFS_FHSM) += fhsm.o ++aufs-$(CONFIG_AUFS_POLL) += poll.o ++aufs-$(CONFIG_AUFS_RDU) += rdu.o ++aufs-$(CONFIG_AUFS_BR_HFSPLUS) += hfsplus.o ++aufs-$(CONFIG_AUFS_DEBUG) += debug.o ++aufs-$(CONFIG_AUFS_MAGIC_SYSRQ) += sysrq.o +diff -Naur null/fs/aufs/module.c linux-5.15.36/fs/aufs/module.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/module.c 2022-05-10 16:51:39.874744219 +0300 +@@ -0,0 +1,273 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * module global variables and operations ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++/* shrinkable realloc */ ++void *au_krealloc(void *p, unsigned int new_sz, gfp_t gfp, int may_shrink) ++{ ++ size_t sz; ++ int diff; ++ ++ sz = 0; ++ diff = -1; ++ if (p) { ++#if 0 /* unused */ ++ if (!new_sz) { ++ au_kfree_rcu(p); ++ p = NULL; ++ goto out; ++ } ++#else ++ AuDebugOn(!new_sz); ++#endif ++ sz = ksize(p); ++ diff = au_kmidx_sub(sz, new_sz); ++ } ++ if (sz && !diff) ++ goto out; ++ ++ if (sz < new_sz) ++ /* expand or SLOB */ ++ p = krealloc(p, new_sz, gfp); ++ else if (new_sz < sz && may_shrink) { ++ /* shrink */ ++ void *q; ++ ++ q = kmalloc(new_sz, gfp); ++ if (q) { ++ if (p) { ++ memcpy(q, p, new_sz); ++ au_kfree_try_rcu(p); ++ } ++ p = q; ++ } else ++ p = NULL; ++ } ++ ++out: ++ return p; ++} ++ ++void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp, ++ int may_shrink) ++{ ++ p = au_krealloc(p, new_sz, gfp, may_shrink); ++ if (p && new_sz > nused) ++ memset(p + nused, 0, new_sz - nused); ++ return p; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * aufs caches ++ */ ++struct kmem_cache *au_cache[AuCache_Last]; ++ ++static void au_cache_fin(void) ++{ ++ int i; ++ ++ /* ++ * Make sure all delayed rcu free inodes are flushed before we ++ * destroy cache. ++ */ ++ rcu_barrier(); ++ ++ /* excluding AuCache_HNOTIFY */ ++ BUILD_BUG_ON(AuCache_HNOTIFY + 1 != AuCache_Last); ++ for (i = 0; i < AuCache_HNOTIFY; i++) { ++ kmem_cache_destroy(au_cache[i]); ++ au_cache[i] = NULL; ++ } ++} ++ ++static int __init au_cache_init(void) ++{ ++ au_cache[AuCache_DINFO] = AuCacheCtor(au_dinfo, au_di_init_once); ++ if (au_cache[AuCache_DINFO]) ++ /* SLAB_DESTROY_BY_RCU */ ++ au_cache[AuCache_ICNTNR] = AuCacheCtor(au_icntnr, ++ au_icntnr_init_once); ++ if (au_cache[AuCache_ICNTNR]) ++ au_cache[AuCache_FINFO] = AuCacheCtor(au_finfo, ++ au_fi_init_once); ++ if (au_cache[AuCache_FINFO]) ++ au_cache[AuCache_VDIR] = AuCache(au_vdir); ++ if (au_cache[AuCache_VDIR]) ++ au_cache[AuCache_DEHSTR] = AuCache(au_vdir_dehstr); ++ if (au_cache[AuCache_DEHSTR]) ++ return 0; ++ ++ au_cache_fin(); ++ return -ENOMEM; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_dir_roflags; ++ ++#ifdef CONFIG_AUFS_SBILIST ++/* ++ * iterate_supers_type() doesn't protect us from ++ * remounting (branch management) ++ */ ++struct hlist_bl_head au_sbilist; ++#endif ++ ++/* ++ * functions for module interface. ++ */ ++MODULE_LICENSE("GPL"); ++/* MODULE_LICENSE("GPL v2"); */ ++MODULE_AUTHOR("Junjiro R. Okajima "); ++MODULE_DESCRIPTION(AUFS_NAME ++ " -- Advanced multi layered unification filesystem"); ++MODULE_VERSION(AUFS_VERSION); ++MODULE_ALIAS_FS(AUFS_NAME); ++ ++/* this module parameter has no meaning when SYSFS is disabled */ ++int sysaufs_brs = 1; ++MODULE_PARM_DESC(brs, "use /fs/aufs/si_*/brN"); ++module_param_named(brs, sysaufs_brs, int, 0444); ++ ++/* this module parameter has no meaning when USER_NS is disabled */ ++bool au_userns; ++MODULE_PARM_DESC(allow_userns, "allow unprivileged to mount under userns"); ++module_param_named(allow_userns, au_userns, bool, 0444); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static char au_esc_chars[0x20 + 3]; /* 0x01-0x20, backslash, del, and NULL */ ++ ++int au_seq_path(struct seq_file *seq, struct path *path) ++{ ++ int err; ++ ++ err = seq_path(seq, path, au_esc_chars); ++ if (err >= 0) ++ err = 0; ++ else ++ err = -ENOMEM; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int __init aufs_init(void) ++{ ++ int err, i; ++ char *p; ++ ++ p = au_esc_chars; ++ for (i = 1; i <= ' '; i++) ++ *p++ = i; ++ *p++ = '\\'; ++ *p++ = '\x7f'; ++ *p = 0; ++ ++ au_dir_roflags = au_file_roflags(O_DIRECTORY | O_LARGEFILE); ++ ++ memcpy(aufs_iop_nogetattr, aufs_iop, sizeof(aufs_iop)); ++ for (i = 0; i < AuIop_Last; i++) ++ aufs_iop_nogetattr[i].getattr = NULL; ++ ++ memset(au_cache, 0, sizeof(au_cache)); /* including hnotify */ ++ ++ au_sbilist_init(); ++ sysaufs_brs_init(); ++ au_debug_init(); ++ au_dy_init(); ++ err = sysaufs_init(); ++ if (unlikely(err)) ++ goto out; ++ err = dbgaufs_init(); ++ if (unlikely(err)) ++ goto out_sysaufs; ++ err = au_procfs_init(); ++ if (unlikely(err)) ++ goto out_dbgaufs; ++ err = au_wkq_init(); ++ if (unlikely(err)) ++ goto out_procfs; ++ err = au_loopback_init(); ++ if (unlikely(err)) ++ goto out_wkq; ++ err = au_hnotify_init(); ++ if (unlikely(err)) ++ goto out_loopback; ++ err = au_sysrq_init(); ++ if (unlikely(err)) ++ goto out_hin; ++ err = au_cache_init(); ++ if (unlikely(err)) ++ goto out_sysrq; ++ ++ aufs_fs_type.fs_flags |= au_userns ? FS_USERNS_MOUNT : 0; ++ err = register_filesystem(&aufs_fs_type); ++ if (unlikely(err)) ++ goto out_cache; ++ ++ /* since we define pr_fmt, call printk directly */ ++ printk(KERN_INFO AUFS_NAME " " AUFS_VERSION "\n"); ++ goto out; /* success */ ++ ++out_cache: ++ au_cache_fin(); ++out_sysrq: ++ au_sysrq_fin(); ++out_hin: ++ au_hnotify_fin(); ++out_loopback: ++ au_loopback_fin(); ++out_wkq: ++ au_wkq_fin(); ++out_procfs: ++ au_procfs_fin(); ++out_dbgaufs: ++ dbgaufs_fin(); ++out_sysaufs: ++ sysaufs_fin(); ++ au_dy_fin(); ++out: ++ return err; ++} ++ ++static void __exit aufs_exit(void) ++{ ++ unregister_filesystem(&aufs_fs_type); ++ au_cache_fin(); ++ au_sysrq_fin(); ++ au_hnotify_fin(); ++ au_loopback_fin(); ++ au_wkq_fin(); ++ au_procfs_fin(); ++ dbgaufs_fin(); ++ sysaufs_fin(); ++ au_dy_fin(); ++} ++ ++module_init(aufs_init); ++module_exit(aufs_exit); +diff -Naur null/fs/aufs/module.h linux-5.15.36/fs/aufs/module.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/module.h 2022-05-10 16:51:39.874744219 +0300 +@@ -0,0 +1,166 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * module initialization and module-global ++ */ ++ ++#ifndef __AUFS_MODULE_H__ ++#define __AUFS_MODULE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "debug.h" ++#include "dentry.h" ++#include "dir.h" ++#include "file.h" ++#include "inode.h" ++ ++struct path; ++struct seq_file; ++ ++/* module parameters */ ++extern int sysaufs_brs; ++extern bool au_userns; ++ ++/* ---------------------------------------------------------------------- */ ++ ++extern int au_dir_roflags; ++ ++void *au_krealloc(void *p, unsigned int new_sz, gfp_t gfp, int may_shrink); ++void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp, ++ int may_shrink); ++ ++/* ++ * Comparing the size of the object with sizeof(struct rcu_head) ++ * case 1: object is always larger ++ * --> au_kfree_rcu() or au_kfree_do_rcu() ++ * case 2: object is always smaller ++ * --> au_kfree_small() ++ * case 3: object can be any size ++ * --> au_kfree_try_rcu() ++ */ ++ ++static inline void au_kfree_do_rcu(const void *p) ++{ ++ struct { ++ struct rcu_head rcu; ++ } *a = (void *)p; ++ ++ kfree_rcu(a, rcu); ++} ++ ++#define au_kfree_rcu(_p) do { \ ++ typeof(_p) p = (_p); \ ++ BUILD_BUG_ON(sizeof(*p) < sizeof(struct rcu_head)); \ ++ if (p) \ ++ au_kfree_do_rcu(p); \ ++ } while (0) ++ ++#define au_kfree_do_sz_test(sz) (sz >= sizeof(struct rcu_head)) ++#define au_kfree_sz_test(p) (p && au_kfree_do_sz_test(ksize(p))) ++ ++static inline void au_kfree_try_rcu(const void *p) ++{ ++ if (!p) ++ return; ++ if (au_kfree_sz_test(p)) ++ au_kfree_do_rcu(p); ++ else ++ kfree(p); ++} ++ ++static inline void au_kfree_small(const void *p) ++{ ++ if (!p) ++ return; ++ AuDebugOn(au_kfree_sz_test(p)); ++ kfree(p); ++} ++ ++static inline int au_kmidx_sub(size_t sz, size_t new_sz) ++{ ++#ifndef CONFIG_SLOB ++ return __kmalloc_index(sz, false) - __kmalloc_index(new_sz, false); ++#else ++ return -1; /* SLOB is untested */ ++#endif ++} ++ ++int au_seq_path(struct seq_file *seq, struct path *path); ++ ++#ifdef CONFIG_PROC_FS ++/* procfs.c */ ++int __init au_procfs_init(void); ++void au_procfs_fin(void); ++#else ++AuStubInt0(au_procfs_init, void); ++AuStubVoid(au_procfs_fin, void); ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* kmem cache */ ++enum { ++ AuCache_DINFO, ++ AuCache_ICNTNR, ++ AuCache_FINFO, ++ AuCache_VDIR, ++ AuCache_DEHSTR, ++ AuCache_HNOTIFY, /* must be last */ ++ AuCache_Last ++}; ++ ++extern struct kmem_cache *au_cache[AuCache_Last]; ++ ++#define AuCacheFlags (SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD) ++#define AuCache(type) KMEM_CACHE(type, AuCacheFlags) ++#define AuCacheCtor(type, ctor) \ ++ kmem_cache_create(#type, sizeof(struct type), \ ++ __alignof__(struct type), AuCacheFlags, ctor) ++ ++#define AuCacheFuncs(name, index) \ ++ static inline struct au_##name *au_cache_alloc_##name(void) \ ++ { return kmem_cache_alloc(au_cache[AuCache_##index], GFP_NOFS); } \ ++ static inline void au_cache_free_##name##_norcu(struct au_##name *p) \ ++ { kmem_cache_free(au_cache[AuCache_##index], p); } \ ++ \ ++ static inline void au_cache_free_##name##_rcu_cb(struct rcu_head *rcu) \ ++ { void *p = rcu; \ ++ p -= offsetof(struct au_##name, rcu); \ ++ kmem_cache_free(au_cache[AuCache_##index], p); } \ ++ static inline void au_cache_free_##name##_rcu(struct au_##name *p) \ ++ { BUILD_BUG_ON(sizeof(struct au_##name) < sizeof(struct rcu_head)); \ ++ call_rcu(&p->rcu, au_cache_free_##name##_rcu_cb); } \ ++ \ ++ static inline void au_cache_free_##name(struct au_##name *p) \ ++ { /* au_cache_free_##name##_norcu(p); */ \ ++ au_cache_free_##name##_rcu(p); } ++ ++AuCacheFuncs(dinfo, DINFO); ++AuCacheFuncs(icntnr, ICNTNR); ++AuCacheFuncs(finfo, FINFO); ++AuCacheFuncs(vdir, VDIR); ++AuCacheFuncs(vdir_dehstr, DEHSTR); ++#ifdef CONFIG_AUFS_HNOTIFY ++AuCacheFuncs(hnotify, HNOTIFY); ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_MODULE_H__ */ +diff -Naur null/fs/aufs/mvdown.c linux-5.15.36/fs/aufs/mvdown.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/mvdown.c 2022-05-10 16:51:39.874744219 +0300 +@@ -0,0 +1,706 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2011-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * move-down, opposite of copy-up ++ */ ++ ++#include "aufs.h" ++ ++struct au_mvd_args { ++ struct { ++ struct super_block *h_sb; ++ struct dentry *h_parent; ++ struct au_hinode *hdir; ++ struct inode *h_dir, *h_inode; ++ struct au_pin pin; ++ } info[AUFS_MVDOWN_NARRAY]; ++ ++ struct aufs_mvdown mvdown; ++ struct dentry *dentry, *parent; ++ struct inode *inode, *dir; ++ struct super_block *sb; ++ aufs_bindex_t bopq, bwh, bfound; ++ unsigned char rename_lock; ++}; ++ ++#define mvd_errno mvdown.au_errno ++#define mvd_bsrc mvdown.stbr[AUFS_MVDOWN_UPPER].bindex ++#define mvd_src_brid mvdown.stbr[AUFS_MVDOWN_UPPER].brid ++#define mvd_bdst mvdown.stbr[AUFS_MVDOWN_LOWER].bindex ++#define mvd_dst_brid mvdown.stbr[AUFS_MVDOWN_LOWER].brid ++ ++#define mvd_h_src_sb info[AUFS_MVDOWN_UPPER].h_sb ++#define mvd_h_src_parent info[AUFS_MVDOWN_UPPER].h_parent ++#define mvd_hdir_src info[AUFS_MVDOWN_UPPER].hdir ++#define mvd_h_src_dir info[AUFS_MVDOWN_UPPER].h_dir ++#define mvd_h_src_inode info[AUFS_MVDOWN_UPPER].h_inode ++#define mvd_pin_src info[AUFS_MVDOWN_UPPER].pin ++ ++#define mvd_h_dst_sb info[AUFS_MVDOWN_LOWER].h_sb ++#define mvd_h_dst_parent info[AUFS_MVDOWN_LOWER].h_parent ++#define mvd_hdir_dst info[AUFS_MVDOWN_LOWER].hdir ++#define mvd_h_dst_dir info[AUFS_MVDOWN_LOWER].h_dir ++#define mvd_h_dst_inode info[AUFS_MVDOWN_LOWER].h_inode ++#define mvd_pin_dst info[AUFS_MVDOWN_LOWER].pin ++ ++#define AU_MVD_PR(flag, ...) do { \ ++ if (flag) \ ++ pr_err(__VA_ARGS__); \ ++ } while (0) ++ ++static int find_lower_writable(struct au_mvd_args *a) ++{ ++ struct super_block *sb; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ sb = a->sb; ++ bindex = a->mvd_bsrc; ++ bbot = au_sbbot(sb); ++ if (a->mvdown.flags & AUFS_MVDOWN_FHSM_LOWER) ++ for (bindex++; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm) ++ && !sb_rdonly(au_br_sb(br))) ++ return bindex; ++ } ++ else if (!(a->mvdown.flags & AUFS_MVDOWN_ROLOWER)) ++ for (bindex++; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!au_br_rdonly(br)) ++ return bindex; ++ } ++ else ++ for (bindex++; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!sb_rdonly(au_br_sb(br))) { ++ if (au_br_rdonly(br)) ++ a->mvdown.flags ++ |= AUFS_MVDOWN_ROLOWER_R; ++ return bindex; ++ } ++ } ++ ++ return -1; ++} ++ ++/* make the parent dir on bdst */ ++static int au_do_mkdir(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ ++ err = 0; ++ a->mvd_hdir_src = au_hi(a->dir, a->mvd_bsrc); ++ a->mvd_hdir_dst = au_hi(a->dir, a->mvd_bdst); ++ a->mvd_h_src_parent = au_h_dptr(a->parent, a->mvd_bsrc); ++ a->mvd_h_dst_parent = NULL; ++ if (au_dbbot(a->parent) >= a->mvd_bdst) ++ a->mvd_h_dst_parent = au_h_dptr(a->parent, a->mvd_bdst); ++ if (!a->mvd_h_dst_parent) { ++ err = au_cpdown_dirs(a->dentry, a->mvd_bdst); ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "cpdown_dirs failed\n"); ++ goto out; ++ } ++ a->mvd_h_dst_parent = au_h_dptr(a->parent, a->mvd_bdst); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* lock them all */ ++static int au_do_lock(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct dentry *h_trap; ++ ++ a->mvd_h_src_sb = au_sbr_sb(a->sb, a->mvd_bsrc); ++ a->mvd_h_dst_sb = au_sbr_sb(a->sb, a->mvd_bdst); ++ err = au_pin(&a->mvd_pin_dst, a->dentry, a->mvd_bdst, ++ au_opt_udba(a->sb), ++ AuPin_MNT_WRITE | AuPin_DI_LOCKED); ++ AuTraceErr(err); ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "pin_dst failed\n"); ++ goto out; ++ } ++ ++ if (a->mvd_h_src_sb != a->mvd_h_dst_sb) { ++ a->rename_lock = 0; ++ au_pin_init(&a->mvd_pin_src, a->dentry, a->mvd_bsrc, ++ AuLsc_DI_PARENT, AuLsc_I_PARENT3, ++ au_opt_udba(a->sb), ++ AuPin_MNT_WRITE | AuPin_DI_LOCKED); ++ err = au_do_pin(&a->mvd_pin_src); ++ AuTraceErr(err); ++ a->mvd_h_src_dir = d_inode(a->mvd_h_src_parent); ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "pin_src failed\n"); ++ goto out_dst; ++ } ++ goto out; /* success */ ++ } ++ ++ a->rename_lock = 1; ++ au_pin_hdir_unlock(&a->mvd_pin_dst); ++ err = au_pin(&a->mvd_pin_src, a->dentry, a->mvd_bsrc, ++ au_opt_udba(a->sb), ++ AuPin_MNT_WRITE | AuPin_DI_LOCKED); ++ AuTraceErr(err); ++ a->mvd_h_src_dir = d_inode(a->mvd_h_src_parent); ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "pin_src failed\n"); ++ au_pin_hdir_lock(&a->mvd_pin_dst); ++ goto out_dst; ++ } ++ au_pin_hdir_unlock(&a->mvd_pin_src); ++ h_trap = vfsub_lock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, ++ a->mvd_h_dst_parent, a->mvd_hdir_dst); ++ if (h_trap) { ++ err = (h_trap != a->mvd_h_src_parent); ++ if (err) ++ err = (h_trap != a->mvd_h_dst_parent); ++ } ++ BUG_ON(err); /* it should never happen */ ++ if (unlikely(a->mvd_h_src_dir != au_pinned_h_dir(&a->mvd_pin_src))) { ++ err = -EBUSY; ++ AuTraceErr(err); ++ vfsub_unlock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, ++ a->mvd_h_dst_parent, a->mvd_hdir_dst); ++ au_pin_hdir_lock(&a->mvd_pin_src); ++ au_unpin(&a->mvd_pin_src); ++ au_pin_hdir_lock(&a->mvd_pin_dst); ++ goto out_dst; ++ } ++ goto out; /* success */ ++ ++out_dst: ++ au_unpin(&a->mvd_pin_dst); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static void au_do_unlock(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ if (!a->rename_lock) ++ au_unpin(&a->mvd_pin_src); ++ else { ++ vfsub_unlock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, ++ a->mvd_h_dst_parent, a->mvd_hdir_dst); ++ au_pin_hdir_lock(&a->mvd_pin_src); ++ au_unpin(&a->mvd_pin_src); ++ au_pin_hdir_lock(&a->mvd_pin_dst); ++ } ++ au_unpin(&a->mvd_pin_dst); ++} ++ ++/* copy-down the file */ ++static int au_do_cpdown(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct au_cp_generic cpg = { ++ .dentry = a->dentry, ++ .bdst = a->mvd_bdst, ++ .bsrc = a->mvd_bsrc, ++ .len = -1, ++ .pin = &a->mvd_pin_dst, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ ++ AuDbg("b%d, b%d\n", cpg.bsrc, cpg.bdst); ++ if (a->mvdown.flags & AUFS_MVDOWN_OWLOWER) ++ au_fset_cpup(cpg.flags, OVERWRITE); ++ if (a->mvdown.flags & AUFS_MVDOWN_ROLOWER) ++ au_fset_cpup(cpg.flags, RWDST); ++ err = au_sio_cpdown_simple(&cpg); ++ if (unlikely(err)) ++ AU_MVD_PR(dmsg, "cpdown failed\n"); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * unlink the whiteout on bdst if exist which may be created by UDBA while we ++ * were sleeping ++ */ ++static int au_do_unlink_wh(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct path h_path; ++ struct au_branch *br; ++ struct inode *delegated; ++ ++ br = au_sbr(a->sb, a->mvd_bdst); ++ h_path.dentry = au_wh_lkup(a->mvd_h_dst_parent, &a->dentry->d_name, br); ++ err = PTR_ERR(h_path.dentry); ++ if (IS_ERR(h_path.dentry)) { ++ AU_MVD_PR(dmsg, "wh_lkup failed\n"); ++ goto out; ++ } ++ ++ err = 0; ++ if (d_is_positive(h_path.dentry)) { ++ h_path.mnt = au_br_mnt(br); ++ delegated = NULL; ++ err = vfsub_unlink(d_inode(a->mvd_h_dst_parent), &h_path, ++ &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ if (unlikely(err)) ++ AU_MVD_PR(dmsg, "wh_unlink failed\n"); ++ } ++ dput(h_path.dentry); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * unlink the topmost h_dentry ++ */ ++static int au_do_unlink(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct path h_path; ++ struct inode *delegated; ++ ++ h_path.mnt = au_sbr_mnt(a->sb, a->mvd_bsrc); ++ h_path.dentry = au_h_dptr(a->dentry, a->mvd_bsrc); ++ delegated = NULL; ++ err = vfsub_unlink(a->mvd_h_src_dir, &h_path, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ if (unlikely(err)) ++ AU_MVD_PR(dmsg, "unlink failed\n"); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* Since mvdown succeeded, we ignore an error of this function */ ++static void au_do_stfs(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct au_branch *br; ++ ++ a->mvdown.flags |= AUFS_MVDOWN_STFS_FAILED; ++ br = au_sbr(a->sb, a->mvd_bsrc); ++ err = au_br_stfs(br, &a->mvdown.stbr[AUFS_MVDOWN_UPPER].stfs); ++ if (!err) { ++ br = au_sbr(a->sb, a->mvd_bdst); ++ a->mvdown.stbr[AUFS_MVDOWN_LOWER].brid = br->br_id; ++ err = au_br_stfs(br, &a->mvdown.stbr[AUFS_MVDOWN_LOWER].stfs); ++ } ++ if (!err) ++ a->mvdown.flags &= ~AUFS_MVDOWN_STFS_FAILED; ++ else ++ AU_MVD_PR(dmsg, "statfs failed (%d), ignored\n", err); ++} ++ ++/* ++ * copy-down the file and unlink the bsrc file. ++ * - unlink the bdst whout if exist ++ * - copy-down the file (with whtmp name and rename) ++ * - unlink the bsrc file ++ */ ++static int au_do_mvdown(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ ++ err = au_do_mkdir(dmsg, a); ++ if (!err) ++ err = au_do_lock(dmsg, a); ++ if (unlikely(err)) ++ goto out; ++ ++ /* ++ * do not revert the activities we made on bdst since they should be ++ * harmless in aufs. ++ */ ++ ++ err = au_do_cpdown(dmsg, a); ++ if (!err) ++ err = au_do_unlink_wh(dmsg, a); ++ if (!err && !(a->mvdown.flags & AUFS_MVDOWN_KUPPER)) ++ err = au_do_unlink(dmsg, a); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ AuDbg("%pd2, 0x%x, %d --> %d\n", ++ a->dentry, a->mvdown.flags, a->mvd_bsrc, a->mvd_bdst); ++ if (find_lower_writable(a) < 0) ++ a->mvdown.flags |= AUFS_MVDOWN_BOTTOM; ++ ++ if (a->mvdown.flags & AUFS_MVDOWN_STFS) ++ au_do_stfs(dmsg, a); ++ ++ /* maintain internal array */ ++ if (!(a->mvdown.flags & AUFS_MVDOWN_KUPPER)) { ++ au_set_h_dptr(a->dentry, a->mvd_bsrc, NULL); ++ au_set_dbtop(a->dentry, a->mvd_bdst); ++ au_set_h_iptr(a->inode, a->mvd_bsrc, NULL, /*flags*/0); ++ au_set_ibtop(a->inode, a->mvd_bdst); ++ } else { ++ /* hide the lower */ ++ au_set_h_dptr(a->dentry, a->mvd_bdst, NULL); ++ au_set_dbbot(a->dentry, a->mvd_bsrc); ++ au_set_h_iptr(a->inode, a->mvd_bdst, NULL, /*flags*/0); ++ au_set_ibbot(a->inode, a->mvd_bsrc); ++ } ++ if (au_dbbot(a->dentry) < a->mvd_bdst) ++ au_set_dbbot(a->dentry, a->mvd_bdst); ++ if (au_ibbot(a->inode) < a->mvd_bdst) ++ au_set_ibbot(a->inode, a->mvd_bdst); ++ ++out_unlock: ++ au_do_unlock(dmsg, a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* make sure the file is idle */ ++static int au_mvd_args_busy(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err, plinked; ++ ++ err = 0; ++ plinked = !!au_opt_test(au_mntflags(a->sb), PLINK); ++ if (au_dbtop(a->dentry) == a->mvd_bsrc ++ && au_dcount(a->dentry) == 1 ++ && atomic_read(&a->inode->i_count) == 1 ++ /* && a->mvd_h_src_inode->i_nlink == 1 */ ++ && (!plinked || !au_plink_test(a->inode)) ++ && a->inode->i_nlink == 1) ++ goto out; ++ ++ err = -EBUSY; ++ AU_MVD_PR(dmsg, ++ "b%d, d{b%d, c%d?}, i{c%d?, l%u}, hi{l%u}, p{%d, %d}\n", ++ a->mvd_bsrc, au_dbtop(a->dentry), au_dcount(a->dentry), ++ atomic_read(&a->inode->i_count), a->inode->i_nlink, ++ a->mvd_h_src_inode->i_nlink, ++ plinked, plinked ? au_plink_test(a->inode) : 0); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* make sure the parent dir is fine */ ++static int au_mvd_args_parent(const unsigned char dmsg, ++ struct au_mvd_args *a) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ ++ err = 0; ++ if (unlikely(au_alive_dir(a->parent))) { ++ err = -ENOENT; ++ AU_MVD_PR(dmsg, "parent dir is dead\n"); ++ goto out; ++ } ++ ++ a->bopq = au_dbdiropq(a->parent); ++ bindex = au_wbr_nonopq(a->dentry, a->mvd_bdst); ++ AuDbg("b%d\n", bindex); ++ if (unlikely((bindex >= 0 && bindex < a->mvd_bdst) ++ || (a->bopq != -1 && a->bopq < a->mvd_bdst))) { ++ err = -EINVAL; ++ a->mvd_errno = EAU_MVDOWN_OPAQUE; ++ AU_MVD_PR(dmsg, "ancestor is opaque b%d, b%d\n", ++ a->bopq, a->mvd_bdst); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_mvd_args_intermediate(const unsigned char dmsg, ++ struct au_mvd_args *a) ++{ ++ int err; ++ struct au_dinfo *dinfo, *tmp; ++ ++ /* lookup the next lower positive entry */ ++ err = -ENOMEM; ++ tmp = au_di_alloc(a->sb, AuLsc_DI_TMP); ++ if (unlikely(!tmp)) ++ goto out; ++ ++ a->bfound = -1; ++ a->bwh = -1; ++ dinfo = au_di(a->dentry); ++ au_di_cp(tmp, dinfo); ++ au_di_swap(tmp, dinfo); ++ ++ /* returns the number of positive dentries */ ++ err = au_lkup_dentry(a->dentry, a->mvd_bsrc + 1, ++ /* AuLkup_IGNORE_PERM */ 0); ++ if (!err) ++ a->bwh = au_dbwh(a->dentry); ++ else if (err > 0) ++ a->bfound = au_dbtop(a->dentry); ++ ++ au_di_swap(tmp, dinfo); ++ au_rw_write_unlock(&tmp->di_rwsem); ++ au_di_free(tmp); ++ if (unlikely(err < 0)) ++ AU_MVD_PR(dmsg, "failed look-up lower\n"); ++ ++ /* ++ * here, we have these cases. ++ * bfound == -1 ++ * no positive dentry under bsrc. there are more sub-cases. ++ * bwh < 0 ++ * there no whiteout, we can safely move-down. ++ * bwh <= bsrc ++ * impossible ++ * bsrc < bwh && bwh < bdst ++ * there is a whiteout on RO branch. cannot proceed. ++ * bwh == bdst ++ * there is a whiteout on the RW target branch. it should ++ * be removed. ++ * bdst < bwh ++ * there is a whiteout somewhere unrelated branch. ++ * -1 < bfound && bfound <= bsrc ++ * impossible. ++ * bfound < bdst ++ * found, but it is on RO branch between bsrc and bdst. cannot ++ * proceed. ++ * bfound == bdst ++ * found, replace it if AUFS_MVDOWN_FORCE is set. otherwise return ++ * error. ++ * bdst < bfound ++ * found, after we create the file on bdst, it will be hidden. ++ */ ++ ++ AuDebugOn(a->bfound == -1 ++ && a->bwh != -1 ++ && a->bwh <= a->mvd_bsrc); ++ AuDebugOn(-1 < a->bfound ++ && a->bfound <= a->mvd_bsrc); ++ ++ err = -EINVAL; ++ if (a->bfound == -1 ++ && a->mvd_bsrc < a->bwh ++ && a->bwh != -1 ++ && a->bwh < a->mvd_bdst) { ++ a->mvd_errno = EAU_MVDOWN_WHITEOUT; ++ AU_MVD_PR(dmsg, "bsrc %d, bdst %d, bfound %d, bwh %d\n", ++ a->mvd_bsrc, a->mvd_bdst, a->bfound, a->bwh); ++ goto out; ++ } else if (a->bfound != -1 && a->bfound < a->mvd_bdst) { ++ a->mvd_errno = EAU_MVDOWN_UPPER; ++ AU_MVD_PR(dmsg, "bdst %d, bfound %d\n", ++ a->mvd_bdst, a->bfound); ++ goto out; ++ } ++ ++ err = 0; /* success */ ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_mvd_args_exist(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ ++ err = 0; ++ if (!(a->mvdown.flags & AUFS_MVDOWN_OWLOWER) ++ && a->bfound == a->mvd_bdst) ++ err = -EEXIST; ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_mvd_args(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct au_branch *br; ++ ++ err = -EISDIR; ++ if (unlikely(S_ISDIR(a->inode->i_mode))) ++ goto out; ++ ++ err = -EINVAL; ++ if (!(a->mvdown.flags & AUFS_MVDOWN_BRID_UPPER)) ++ a->mvd_bsrc = au_ibtop(a->inode); ++ else { ++ a->mvd_bsrc = au_br_index(a->sb, a->mvd_src_brid); ++ if (unlikely(a->mvd_bsrc < 0 ++ || (a->mvd_bsrc < au_dbtop(a->dentry) ++ || au_dbbot(a->dentry) < a->mvd_bsrc ++ || !au_h_dptr(a->dentry, a->mvd_bsrc)) ++ || (a->mvd_bsrc < au_ibtop(a->inode) ++ || au_ibbot(a->inode) < a->mvd_bsrc ++ || !au_h_iptr(a->inode, a->mvd_bsrc)))) { ++ a->mvd_errno = EAU_MVDOWN_NOUPPER; ++ AU_MVD_PR(dmsg, "no upper\n"); ++ goto out; ++ } ++ } ++ if (unlikely(a->mvd_bsrc == au_sbbot(a->sb))) { ++ a->mvd_errno = EAU_MVDOWN_BOTTOM; ++ AU_MVD_PR(dmsg, "on the bottom\n"); ++ goto out; ++ } ++ a->mvd_h_src_inode = au_h_iptr(a->inode, a->mvd_bsrc); ++ br = au_sbr(a->sb, a->mvd_bsrc); ++ err = au_br_rdonly(br); ++ if (!(a->mvdown.flags & AUFS_MVDOWN_ROUPPER)) { ++ if (unlikely(err)) ++ goto out; ++ } else if (!(vfsub_native_ro(a->mvd_h_src_inode) ++ || IS_APPEND(a->mvd_h_src_inode))) { ++ if (err) ++ a->mvdown.flags |= AUFS_MVDOWN_ROUPPER_R; ++ /* go on */ ++ } else ++ goto out; ++ ++ err = -EINVAL; ++ if (!(a->mvdown.flags & AUFS_MVDOWN_BRID_LOWER)) { ++ a->mvd_bdst = find_lower_writable(a); ++ if (unlikely(a->mvd_bdst < 0)) { ++ a->mvd_errno = EAU_MVDOWN_BOTTOM; ++ AU_MVD_PR(dmsg, "no writable lower branch\n"); ++ goto out; ++ } ++ } else { ++ a->mvd_bdst = au_br_index(a->sb, a->mvd_dst_brid); ++ if (unlikely(a->mvd_bdst < 0 ++ || au_sbbot(a->sb) < a->mvd_bdst)) { ++ a->mvd_errno = EAU_MVDOWN_NOLOWERBR; ++ AU_MVD_PR(dmsg, "no lower brid\n"); ++ goto out; ++ } ++ } ++ ++ err = au_mvd_args_busy(dmsg, a); ++ if (!err) ++ err = au_mvd_args_parent(dmsg, a); ++ if (!err) ++ err = au_mvd_args_intermediate(dmsg, a); ++ if (!err) ++ err = au_mvd_args_exist(dmsg, a); ++ if (!err) ++ AuDbg("b%d, b%d\n", a->mvd_bsrc, a->mvd_bdst); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *uarg) ++{ ++ int err, e; ++ unsigned char dmsg; ++ struct au_mvd_args *args; ++ struct inode *inode; ++ ++ inode = d_inode(dentry); ++ err = -EPERM; ++ if (unlikely(!capable(CAP_SYS_ADMIN))) ++ goto out; ++ ++ err = -ENOMEM; ++ args = kmalloc(sizeof(*args), GFP_NOFS); ++ if (unlikely(!args)) ++ goto out; ++ ++ err = copy_from_user(&args->mvdown, uarg, sizeof(args->mvdown)); ++ if (!err) ++ /* VERIFY_WRITE */ ++ err = !access_ok(uarg, sizeof(*uarg)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out_free; ++ } ++ AuDbg("flags 0x%x\n", args->mvdown.flags); ++ args->mvdown.flags &= ~(AUFS_MVDOWN_ROLOWER_R | AUFS_MVDOWN_ROUPPER_R); ++ args->mvdown.au_errno = 0; ++ args->dentry = dentry; ++ args->inode = inode; ++ args->sb = dentry->d_sb; ++ ++ err = -ENOENT; ++ dmsg = !!(args->mvdown.flags & AUFS_MVDOWN_DMSG); ++ args->parent = dget_parent(dentry); ++ args->dir = d_inode(args->parent); ++ inode_lock_nested(args->dir, I_MUTEX_PARENT); ++ dput(args->parent); ++ if (unlikely(args->parent != dentry->d_parent)) { ++ AU_MVD_PR(dmsg, "parent dir is moved\n"); ++ goto out_dir; ++ } ++ ++ inode_lock_nested(inode, I_MUTEX_CHILD); ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_NOPLMW); ++ if (unlikely(err)) ++ goto out_inode; ++ ++ di_write_lock_parent(args->parent); ++ err = au_mvd_args(dmsg, args); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ err = au_do_mvdown(dmsg, args); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ au_cpup_attr_timesizes(args->dir); ++ au_cpup_attr_timesizes(inode); ++ if (!(args->mvdown.flags & AUFS_MVDOWN_KUPPER)) ++ au_cpup_igen(inode, au_h_iptr(inode, args->mvd_bdst)); ++ /* au_digen_dec(dentry); */ ++ ++out_parent: ++ di_write_unlock(args->parent); ++ aufs_read_unlock(dentry, AuLock_DW); ++out_inode: ++ inode_unlock(inode); ++out_dir: ++ inode_unlock(args->dir); ++out_free: ++ e = copy_to_user(uarg, &args->mvdown, sizeof(args->mvdown)); ++ if (unlikely(e)) ++ err = -EFAULT; ++ au_kfree_rcu(args); ++out: ++ AuTraceErr(err); ++ return err; ++} +diff -Naur null/fs/aufs/opts.c linux-5.15.36/fs/aufs/opts.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/opts.c 2022-05-10 16:51:39.875744219 +0300 +@@ -0,0 +1,1032 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * mount options/flags ++ */ ++ ++#include /* a distribution requires */ ++#include ++#include "aufs.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++static const char *au_parser_pattern(int val, match_table_t tbl) ++{ ++ struct match_token *p; ++ ++ p = tbl; ++ while (p->pattern) { ++ if (p->token == val) ++ return p->pattern; ++ p++; ++ } ++ BUG(); ++ return "??"; ++} ++ ++static const char *au_optstr(int *val, match_table_t tbl) ++{ ++ struct match_token *p; ++ int v; ++ ++ v = *val; ++ if (!v) ++ goto out; ++ p = tbl; ++ while (p->pattern) { ++ if (p->token ++ && (v & p->token) == p->token) { ++ *val &= ~p->token; ++ return p->pattern; ++ } ++ p++; ++ } ++ ++out: ++ return NULL; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static match_table_t brperm = { ++ {AuBrPerm_RO, AUFS_BRPERM_RO}, ++ {AuBrPerm_RR, AUFS_BRPERM_RR}, ++ {AuBrPerm_RW, AUFS_BRPERM_RW}, ++ {0, NULL} ++}; ++ ++static match_table_t brattr = { ++ /* general */ ++ {AuBrAttr_COO_REG, AUFS_BRATTR_COO_REG}, ++ {AuBrAttr_COO_ALL, AUFS_BRATTR_COO_ALL}, ++ /* 'unpin' attrib is meaningless since linux-3.18-rc1 */ ++ {AuBrAttr_UNPIN, AUFS_BRATTR_UNPIN}, ++#ifdef CONFIG_AUFS_FHSM ++ {AuBrAttr_FHSM, AUFS_BRATTR_FHSM}, ++#endif ++#ifdef CONFIG_AUFS_XATTR ++ {AuBrAttr_ICEX, AUFS_BRATTR_ICEX}, ++ {AuBrAttr_ICEX_SEC, AUFS_BRATTR_ICEX_SEC}, ++ {AuBrAttr_ICEX_SYS, AUFS_BRATTR_ICEX_SYS}, ++ {AuBrAttr_ICEX_TR, AUFS_BRATTR_ICEX_TR}, ++ {AuBrAttr_ICEX_USR, AUFS_BRATTR_ICEX_USR}, ++ {AuBrAttr_ICEX_OTH, AUFS_BRATTR_ICEX_OTH}, ++#endif ++ ++ /* ro/rr branch */ ++ {AuBrRAttr_WH, AUFS_BRRATTR_WH}, ++ ++ /* rw branch */ ++ {AuBrWAttr_MOO, AUFS_BRWATTR_MOO}, ++ {AuBrWAttr_NoLinkWH, AUFS_BRWATTR_NLWH}, ++ ++ {0, NULL} ++}; ++ ++static int br_attr_val(char *str, match_table_t table, substring_t args[]) ++{ ++ int attr, v; ++ char *p; ++ ++ attr = 0; ++ do { ++ p = strchr(str, '+'); ++ if (p) ++ *p = 0; ++ v = match_token(str, table, args); ++ if (v) { ++ if (v & AuBrAttr_CMOO_Mask) ++ attr &= ~AuBrAttr_CMOO_Mask; ++ attr |= v; ++ } else { ++ if (p) ++ *p = '+'; ++ pr_warn("ignored branch attribute %s\n", str); ++ break; ++ } ++ if (p) ++ str = p + 1; ++ } while (p); ++ ++ return attr; ++} ++ ++static int au_do_optstr_br_attr(au_br_perm_str_t *str, int perm) ++{ ++ int sz; ++ const char *p; ++ char *q; ++ ++ q = str->a; ++ *q = 0; ++ p = au_optstr(&perm, brattr); ++ if (p) { ++ sz = strlen(p); ++ memcpy(q, p, sz + 1); ++ q += sz; ++ } else ++ goto out; ++ ++ do { ++ p = au_optstr(&perm, brattr); ++ if (p) { ++ *q++ = '+'; ++ sz = strlen(p); ++ memcpy(q, p, sz + 1); ++ q += sz; ++ } ++ } while (p); ++ ++out: ++ return q - str->a; ++} ++ ++int au_br_perm_val(char *perm) ++{ ++ int val, bad, sz; ++ char *p; ++ substring_t args[MAX_OPT_ARGS]; ++ au_br_perm_str_t attr; ++ ++ p = strchr(perm, '+'); ++ if (p) ++ *p = 0; ++ val = match_token(perm, brperm, args); ++ if (!val) { ++ if (p) ++ *p = '+'; ++ pr_warn("ignored branch permission %s\n", perm); ++ val = AuBrPerm_RO; ++ goto out; ++ } ++ if (!p) ++ goto out; ++ ++ val |= br_attr_val(p + 1, brattr, args); ++ ++ bad = 0; ++ switch (val & AuBrPerm_Mask) { ++ case AuBrPerm_RO: ++ case AuBrPerm_RR: ++ bad = val & AuBrWAttr_Mask; ++ val &= ~AuBrWAttr_Mask; ++ break; ++ case AuBrPerm_RW: ++ bad = val & AuBrRAttr_Mask; ++ val &= ~AuBrRAttr_Mask; ++ break; ++ } ++ ++ /* ++ * 'unpin' attrib becomes meaningless since linux-3.18-rc1, but aufs ++ * does not treat it as an error, just warning. ++ * this is a tiny guard for the user operation. ++ */ ++ if (val & AuBrAttr_UNPIN) { ++ bad |= AuBrAttr_UNPIN; ++ val &= ~AuBrAttr_UNPIN; ++ } ++ ++ if (unlikely(bad)) { ++ sz = au_do_optstr_br_attr(&attr, bad); ++ AuDebugOn(!sz); ++ pr_warn("ignored branch attribute %s\n", attr.a); ++ } ++ ++out: ++ return val; ++} ++ ++void au_optstr_br_perm(au_br_perm_str_t *str, int perm) ++{ ++ au_br_perm_str_t attr; ++ const char *p; ++ char *q; ++ int sz; ++ ++ q = str->a; ++ p = au_optstr(&perm, brperm); ++ AuDebugOn(!p || !*p); ++ sz = strlen(p); ++ memcpy(q, p, sz + 1); ++ q += sz; ++ ++ sz = au_do_optstr_br_attr(&attr, perm); ++ if (sz) { ++ *q++ = '+'; ++ memcpy(q, attr.a, sz + 1); ++ } ++ ++ AuDebugOn(strlen(str->a) >= sizeof(str->a)); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static match_table_t udbalevel = { ++ {AuOpt_UDBA_REVAL, "reval"}, ++ {AuOpt_UDBA_NONE, "none"}, ++#ifdef CONFIG_AUFS_HNOTIFY ++ {AuOpt_UDBA_HNOTIFY, "notify"}, /* abstraction */ ++#ifdef CONFIG_AUFS_HFSNOTIFY ++ {AuOpt_UDBA_HNOTIFY, "fsnotify"}, ++#endif ++#endif ++ {-1, NULL} ++}; ++ ++int au_udba_val(char *str) ++{ ++ substring_t args[MAX_OPT_ARGS]; ++ ++ return match_token(str, udbalevel, args); ++} ++ ++const char *au_optstr_udba(int udba) ++{ ++ return au_parser_pattern(udba, udbalevel); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static match_table_t au_wbr_create_policy = { ++ {AuWbrCreate_TDP, "tdp"}, ++ {AuWbrCreate_TDP, "top-down-parent"}, ++ {AuWbrCreate_RR, "rr"}, ++ {AuWbrCreate_RR, "round-robin"}, ++ {AuWbrCreate_MFS, "mfs"}, ++ {AuWbrCreate_MFS, "most-free-space"}, ++ {AuWbrCreate_MFSV, "mfs:%d"}, ++ {AuWbrCreate_MFSV, "most-free-space:%d"}, ++ ++ /* top-down regardless the parent, and then mfs */ ++ {AuWbrCreate_TDMFS, "tdmfs:%d"}, ++ {AuWbrCreate_TDMFSV, "tdmfs:%d:%d"}, ++ ++ {AuWbrCreate_MFSRR, "mfsrr:%d"}, ++ {AuWbrCreate_MFSRRV, "mfsrr:%d:%d"}, ++ {AuWbrCreate_PMFS, "pmfs"}, ++ {AuWbrCreate_PMFSV, "pmfs:%d"}, ++ {AuWbrCreate_PMFSRR, "pmfsrr:%d"}, ++ {AuWbrCreate_PMFSRRV, "pmfsrr:%d:%d"}, ++ ++ {-1, NULL} ++}; ++ ++static int au_wbr_mfs_wmark(substring_t *arg, char *str, ++ struct au_opt_wbr_create *create) ++{ ++ int err; ++ unsigned long long ull; ++ ++ err = 0; ++ if (!match_u64(arg, &ull)) ++ create->mfsrr_watermark = ull; ++ else { ++ pr_err("bad integer in %s\n", str); ++ err = -EINVAL; ++ } ++ ++ return err; ++} ++ ++static int au_wbr_mfs_sec(substring_t *arg, char *str, ++ struct au_opt_wbr_create *create) ++{ ++ int n, err; ++ ++ err = 0; ++ if (!match_int(arg, &n) && 0 <= n && n <= AUFS_MFS_MAX_SEC) ++ create->mfs_second = n; ++ else { ++ pr_err("bad integer in %s\n", str); ++ err = -EINVAL; ++ } ++ ++ return err; ++} ++ ++int au_wbr_create_val(char *str, struct au_opt_wbr_create *create) ++{ ++ int err, e; ++ substring_t args[MAX_OPT_ARGS]; ++ ++ err = match_token(str, au_wbr_create_policy, args); ++ create->wbr_create = err; ++ switch (err) { ++ case AuWbrCreate_MFSRRV: ++ case AuWbrCreate_TDMFSV: ++ case AuWbrCreate_PMFSRRV: ++ e = au_wbr_mfs_wmark(&args[0], str, create); ++ if (!e) ++ e = au_wbr_mfs_sec(&args[1], str, create); ++ if (unlikely(e)) ++ err = e; ++ break; ++ case AuWbrCreate_MFSRR: ++ case AuWbrCreate_TDMFS: ++ case AuWbrCreate_PMFSRR: ++ e = au_wbr_mfs_wmark(&args[0], str, create); ++ if (unlikely(e)) { ++ err = e; ++ break; ++ } ++ fallthrough; ++ case AuWbrCreate_MFS: ++ case AuWbrCreate_PMFS: ++ create->mfs_second = AUFS_MFS_DEF_SEC; ++ break; ++ case AuWbrCreate_MFSV: ++ case AuWbrCreate_PMFSV: ++ e = au_wbr_mfs_sec(&args[0], str, create); ++ if (unlikely(e)) ++ err = e; ++ break; ++ } ++ ++ return err; ++} ++ ++const char *au_optstr_wbr_create(int wbr_create) ++{ ++ return au_parser_pattern(wbr_create, au_wbr_create_policy); ++} ++ ++static match_table_t au_wbr_copyup_policy = { ++ {AuWbrCopyup_TDP, "tdp"}, ++ {AuWbrCopyup_TDP, "top-down-parent"}, ++ {AuWbrCopyup_BUP, "bup"}, ++ {AuWbrCopyup_BUP, "bottom-up-parent"}, ++ {AuWbrCopyup_BU, "bu"}, ++ {AuWbrCopyup_BU, "bottom-up"}, ++ {-1, NULL} ++}; ++ ++int au_wbr_copyup_val(char *str) ++{ ++ substring_t args[MAX_OPT_ARGS]; ++ ++ return match_token(str, au_wbr_copyup_policy, args); ++} ++ ++const char *au_optstr_wbr_copyup(int wbr_copyup) ++{ ++ return au_parser_pattern(wbr_copyup, au_wbr_copyup_policy); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_opt_add(struct au_opt *opt, char *opt_str, unsigned long sb_flags, ++ aufs_bindex_t bindex) ++{ ++ int err; ++ struct au_opt_add *add = &opt->add; ++ char *p; ++ ++ add->bindex = bindex; ++ add->perm = AuBrPerm_RO; ++ add->pathname = opt_str; ++ p = strchr(opt_str, '='); ++ if (p) { ++ *p++ = 0; ++ if (*p) ++ add->perm = au_br_perm_val(p); ++ } ++ ++ err = vfsub_kern_path(add->pathname, AuOpt_LkupDirFlags, &add->path); ++ if (!err) { ++ if (!p) { ++ add->perm = AuBrPerm_RO; ++ if (au_test_fs_rr(add->path.dentry->d_sb)) ++ add->perm = AuBrPerm_RR; ++ else if (!bindex && !(sb_flags & SB_RDONLY)) ++ add->perm = AuBrPerm_RW; ++ } ++ opt->type = Opt_add; ++ goto out; ++ } ++ pr_err("lookup failed %s (%d)\n", add->pathname, err); ++ err = -EINVAL; ++ ++out: ++ return err; ++} ++ ++static int au_opt_wbr_create(struct super_block *sb, ++ struct au_opt_wbr_create *create) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ err = 1; /* handled */ ++ sbinfo = au_sbi(sb); ++ if (sbinfo->si_wbr_create_ops->fin) { ++ err = sbinfo->si_wbr_create_ops->fin(sb); ++ if (!err) ++ err = 1; ++ } ++ ++ sbinfo->si_wbr_create = create->wbr_create; ++ sbinfo->si_wbr_create_ops = au_wbr_create_ops + create->wbr_create; ++ switch (create->wbr_create) { ++ case AuWbrCreate_MFSRRV: ++ case AuWbrCreate_MFSRR: ++ case AuWbrCreate_TDMFS: ++ case AuWbrCreate_TDMFSV: ++ case AuWbrCreate_PMFSRR: ++ case AuWbrCreate_PMFSRRV: ++ sbinfo->si_wbr_mfs.mfsrr_watermark = create->mfsrr_watermark; ++ fallthrough; ++ case AuWbrCreate_MFS: ++ case AuWbrCreate_MFSV: ++ case AuWbrCreate_PMFS: ++ case AuWbrCreate_PMFSV: ++ sbinfo->si_wbr_mfs.mfs_expire ++ = msecs_to_jiffies(create->mfs_second * MSEC_PER_SEC); ++ break; ++ } ++ ++ if (sbinfo->si_wbr_create_ops->init) ++ sbinfo->si_wbr_create_ops->init(sb); /* ignore */ ++ ++ return err; ++} ++ ++/* ++ * returns, ++ * plus: processed without an error ++ * zero: unprocessed ++ */ ++static int au_opt_simple(struct super_block *sb, struct au_opt *opt, ++ struct au_opts *opts) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ err = 1; /* handled */ ++ sbinfo = au_sbi(sb); ++ switch (opt->type) { ++ case Opt_udba: ++ sbinfo->si_mntflags &= ~AuOptMask_UDBA; ++ sbinfo->si_mntflags |= opt->udba; ++ opts->given_udba |= opt->udba; ++ break; ++ ++ case Opt_plink: ++ if (opt->tf) ++ au_opt_set(sbinfo->si_mntflags, PLINK); ++ else { ++ if (au_opt_test(sbinfo->si_mntflags, PLINK)) ++ au_plink_put(sb, /*verbose*/1); ++ au_opt_clr(sbinfo->si_mntflags, PLINK); ++ } ++ break; ++ case Opt_list_plink: ++ if (au_opt_test(sbinfo->si_mntflags, PLINK)) ++ au_plink_list(sb); ++ break; ++ ++ case Opt_dio: ++ if (opt->tf) { ++ au_opt_set(sbinfo->si_mntflags, DIO); ++ au_fset_opts(opts->flags, REFRESH_DYAOP); ++ } else { ++ au_opt_clr(sbinfo->si_mntflags, DIO); ++ au_fset_opts(opts->flags, REFRESH_DYAOP); ++ } ++ break; ++ ++ case Opt_fhsm_sec: ++ au_fhsm_set(sbinfo, opt->fhsm_second); ++ break; ++ ++ case Opt_diropq_a: ++ au_opt_set(sbinfo->si_mntflags, ALWAYS_DIROPQ); ++ break; ++ case Opt_diropq_w: ++ au_opt_clr(sbinfo->si_mntflags, ALWAYS_DIROPQ); ++ break; ++ ++ case Opt_warn_perm: ++ if (opt->tf) ++ au_opt_set(sbinfo->si_mntflags, WARN_PERM); ++ else ++ au_opt_clr(sbinfo->si_mntflags, WARN_PERM); ++ break; ++ ++ case Opt_verbose: ++ if (opt->tf) ++ au_opt_set(sbinfo->si_mntflags, VERBOSE); ++ else ++ au_opt_clr(sbinfo->si_mntflags, VERBOSE); ++ break; ++ ++ case Opt_sum: ++ if (opt->tf) ++ au_opt_set(sbinfo->si_mntflags, SUM); ++ else { ++ au_opt_clr(sbinfo->si_mntflags, SUM); ++ au_opt_clr(sbinfo->si_mntflags, SUM_W); ++ } ++ break; ++ case Opt_wsum: ++ au_opt_clr(sbinfo->si_mntflags, SUM); ++ au_opt_set(sbinfo->si_mntflags, SUM_W); ++ break; ++ ++ case Opt_wbr_create: ++ err = au_opt_wbr_create(sb, &opt->wbr_create); ++ break; ++ case Opt_wbr_copyup: ++ sbinfo->si_wbr_copyup = opt->wbr_copyup; ++ sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + opt->wbr_copyup; ++ break; ++ ++ case Opt_dirwh: ++ sbinfo->si_dirwh = opt->dirwh; ++ break; ++ ++ case Opt_rdcache: ++ sbinfo->si_rdcache ++ = msecs_to_jiffies(opt->rdcache * MSEC_PER_SEC); ++ break; ++ case Opt_rdblk: ++ sbinfo->si_rdblk = opt->rdblk; ++ break; ++ case Opt_rdhash: ++ sbinfo->si_rdhash = opt->rdhash; ++ break; ++ ++ case Opt_shwh: ++ if (opt->tf) ++ au_opt_set(sbinfo->si_mntflags, SHWH); ++ else ++ au_opt_clr(sbinfo->si_mntflags, SHWH); ++ break; ++ ++ case Opt_dirperm1: ++ if (opt->tf) ++ au_opt_set(sbinfo->si_mntflags, DIRPERM1); ++ else ++ au_opt_clr(sbinfo->si_mntflags, DIRPERM1); ++ break; ++ ++ case Opt_trunc_xino: ++ if (opt->tf) ++ au_opt_set(sbinfo->si_mntflags, TRUNC_XINO); ++ else ++ au_opt_clr(sbinfo->si_mntflags, TRUNC_XINO); ++ break; ++ ++ case Opt_trunc_xino_path: ++ case Opt_itrunc_xino: ++ err = au_xino_trunc(sb, opt->xino_itrunc.bindex, ++ /*idx_begin*/0); ++ if (!err) ++ err = 1; ++ break; ++ ++ case Opt_trunc_xib: ++ if (opt->tf) ++ au_fset_opts(opts->flags, TRUNC_XIB); ++ else ++ au_fclr_opts(opts->flags, TRUNC_XIB); ++ break; ++ ++ case Opt_dirren: ++ err = 1; ++ if (opt->tf) { ++ if (!au_opt_test(sbinfo->si_mntflags, DIRREN)) { ++ err = au_dr_opt_set(sb); ++ if (!err) ++ err = 1; ++ } ++ if (err == 1) ++ au_opt_set(sbinfo->si_mntflags, DIRREN); ++ } else { ++ if (au_opt_test(sbinfo->si_mntflags, DIRREN)) { ++ err = au_dr_opt_clr(sb, au_ftest_opts(opts->flags, ++ DR_FLUSHED)); ++ if (!err) ++ err = 1; ++ } ++ if (err == 1) ++ au_opt_clr(sbinfo->si_mntflags, DIRREN); ++ } ++ break; ++ ++ case Opt_acl: ++ if (opt->tf) ++ sb->s_flags |= SB_POSIXACL; ++ else ++ sb->s_flags &= ~SB_POSIXACL; ++ break; ++ ++ default: ++ err = 0; ++ break; ++ } ++ ++ return err; ++} ++ ++/* ++ * returns tri-state. ++ * plus: processed without an error ++ * zero: unprocessed ++ * minus: error ++ */ ++static int au_opt_br(struct super_block *sb, struct au_opt *opt, ++ struct au_opts *opts) ++{ ++ int err, do_refresh; ++ ++ err = 0; ++ switch (opt->type) { ++ case Opt_append: ++ opt->add.bindex = au_sbbot(sb) + 1; ++ if (opt->add.bindex < 0) ++ opt->add.bindex = 0; ++ goto add; ++ /* Always goto add, not fallthrough */ ++ case Opt_prepend: ++ opt->add.bindex = 0; ++ fallthrough; ++ add: /* indented label */ ++ case Opt_add: ++ err = au_br_add(sb, &opt->add, ++ au_ftest_opts(opts->flags, REMOUNT)); ++ if (!err) { ++ err = 1; ++ au_fset_opts(opts->flags, REFRESH); ++ } ++ break; ++ ++ case Opt_del: ++ case Opt_idel: ++ err = au_br_del(sb, &opt->del, ++ au_ftest_opts(opts->flags, REMOUNT)); ++ if (!err) { ++ err = 1; ++ au_fset_opts(opts->flags, TRUNC_XIB); ++ au_fset_opts(opts->flags, REFRESH); ++ } ++ break; ++ ++ case Opt_mod: ++ case Opt_imod: ++ err = au_br_mod(sb, &opt->mod, ++ au_ftest_opts(opts->flags, REMOUNT), ++ &do_refresh); ++ if (!err) { ++ err = 1; ++ if (do_refresh) ++ au_fset_opts(opts->flags, REFRESH); ++ } ++ break; ++ } ++ return err; ++} ++ ++static int au_opt_xino(struct super_block *sb, struct au_opt *opt, ++ struct au_opt_xino **opt_xino, ++ struct au_opts *opts) ++{ ++ int err; ++ ++ err = 0; ++ switch (opt->type) { ++ case Opt_xino: ++ err = au_xino_set(sb, &opt->xino, ++ !!au_ftest_opts(opts->flags, REMOUNT)); ++ if (!err) ++ *opt_xino = &opt->xino; ++ break; ++ case Opt_noxino: ++ au_xino_clr(sb); ++ *opt_xino = (void *)-1; ++ break; ++ } ++ ++ return err; ++} ++ ++int au_opts_verify(struct super_block *sb, unsigned long sb_flags, ++ unsigned int pending) ++{ ++ int err, fhsm; ++ aufs_bindex_t bindex, bbot; ++ unsigned char do_plink, skip, do_free, can_no_dreval; ++ struct au_branch *br; ++ struct au_wbr *wbr; ++ struct dentry *root, *dentry; ++ struct inode *dir, *h_dir; ++ struct au_sbinfo *sbinfo; ++ struct au_hinode *hdir; ++ ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!(sbinfo->si_mntflags & AuOptMask_UDBA)); ++ ++ if (!(sb_flags & SB_RDONLY)) { ++ if (unlikely(!au_br_writable(au_sbr_perm(sb, 0)))) ++ pr_warn("first branch should be rw\n"); ++ if (unlikely(au_opt_test(sbinfo->si_mntflags, SHWH))) ++ pr_warn_once("shwh should be used with ro\n"); ++ } ++ ++ if (au_opt_test((sbinfo->si_mntflags | pending), UDBA_HNOTIFY) ++ && !au_opt_test(sbinfo->si_mntflags, XINO)) ++ pr_warn_once("udba=*notify requires xino\n"); ++ ++ if (au_opt_test(sbinfo->si_mntflags, DIRPERM1)) ++ pr_warn_once("dirperm1 breaks the protection" ++ " by the permission bits on the lower branch\n"); ++ ++ err = 0; ++ fhsm = 0; ++ root = sb->s_root; ++ dir = d_inode(root); ++ do_plink = !!au_opt_test(sbinfo->si_mntflags, PLINK); ++ can_no_dreval = !!au_opt_test((sbinfo->si_mntflags | pending), ++ UDBA_NONE); ++ bbot = au_sbbot(sb); ++ for (bindex = 0; !err && bindex <= bbot; bindex++) { ++ skip = 0; ++ h_dir = au_h_iptr(dir, bindex); ++ br = au_sbr(sb, bindex); ++ ++ if ((br->br_perm & AuBrAttr_ICEX) ++ && !h_dir->i_op->listxattr) ++ br->br_perm &= ~AuBrAttr_ICEX; ++#if 0 /* untested */ ++ if ((br->br_perm & AuBrAttr_ICEX_SEC) ++ && (au_br_sb(br)->s_flags & SB_NOSEC)) ++ br->br_perm &= ~AuBrAttr_ICEX_SEC; ++#endif ++ ++ do_free = 0; ++ wbr = br->br_wbr; ++ if (wbr) ++ wbr_wh_read_lock(wbr); ++ ++ if (!au_br_writable(br->br_perm)) { ++ do_free = !!wbr; ++ skip = (!wbr ++ || (!wbr->wbr_whbase ++ && !wbr->wbr_plink ++ && !wbr->wbr_orph)); ++ } else if (!au_br_wh_linkable(br->br_perm)) { ++ /* skip = (!br->br_whbase && !br->br_orph); */ ++ skip = (!wbr || !wbr->wbr_whbase); ++ if (skip && wbr) { ++ if (do_plink) ++ skip = !!wbr->wbr_plink; ++ else ++ skip = !wbr->wbr_plink; ++ } ++ } else { ++ /* skip = (br->br_whbase && br->br_ohph); */ ++ skip = (wbr && wbr->wbr_whbase); ++ if (skip) { ++ if (do_plink) ++ skip = !!wbr->wbr_plink; ++ else ++ skip = !wbr->wbr_plink; ++ } ++ } ++ if (wbr) ++ wbr_wh_read_unlock(wbr); ++ ++ if (can_no_dreval) { ++ dentry = br->br_path.dentry; ++ spin_lock(&dentry->d_lock); ++ if (dentry->d_flags & ++ (DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE)) ++ can_no_dreval = 0; ++ spin_unlock(&dentry->d_lock); ++ } ++ ++ if (au_br_fhsm(br->br_perm)) { ++ fhsm++; ++ AuDebugOn(!br->br_fhsm); ++ } ++ ++ if (skip) ++ continue; ++ ++ hdir = au_hi(dir, bindex); ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ if (wbr) ++ wbr_wh_write_lock(wbr); ++ err = au_wh_init(br, sb); ++ if (wbr) ++ wbr_wh_write_unlock(wbr); ++ au_hn_inode_unlock(hdir); ++ ++ if (!err && do_free) { ++ au_kfree_rcu(wbr); ++ br->br_wbr = NULL; ++ } ++ } ++ ++ if (can_no_dreval) ++ au_fset_si(sbinfo, NO_DREVAL); ++ else ++ au_fclr_si(sbinfo, NO_DREVAL); ++ ++ if (fhsm >= 2) { ++ au_fset_si(sbinfo, FHSM); ++ for (bindex = bbot; bindex >= 0; bindex--) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm)) { ++ au_fhsm_set_bottom(sb, bindex); ++ break; ++ } ++ } ++ } else { ++ au_fclr_si(sbinfo, FHSM); ++ au_fhsm_set_bottom(sb, -1); ++ } ++ ++ return err; ++} ++ ++int au_opts_mount(struct super_block *sb, struct au_opts *opts) ++{ ++ int err; ++ unsigned int tmp; ++ aufs_bindex_t bindex, bbot; ++ struct au_opt *opt; ++ struct au_opt_xino *opt_xino, xino; ++ struct au_sbinfo *sbinfo; ++ struct au_branch *br; ++ struct inode *dir; ++ ++ SiMustWriteLock(sb); ++ ++ err = 0; ++ opt_xino = NULL; ++ opt = opts->opt; ++ while (err >= 0 && opt->type != Opt_tail) ++ err = au_opt_simple(sb, opt++, opts); ++ if (err > 0) ++ err = 0; ++ else if (unlikely(err < 0)) ++ goto out; ++ ++ /* disable xino and udba temporary */ ++ sbinfo = au_sbi(sb); ++ tmp = sbinfo->si_mntflags; ++ au_opt_clr(sbinfo->si_mntflags, XINO); ++ au_opt_set_udba(sbinfo->si_mntflags, UDBA_REVAL); ++ ++ opt = opts->opt; ++ while (err >= 0 && opt->type != Opt_tail) ++ err = au_opt_br(sb, opt++, opts); ++ if (err > 0) ++ err = 0; ++ else if (unlikely(err < 0)) ++ goto out; ++ ++ bbot = au_sbbot(sb); ++ if (unlikely(bbot < 0)) { ++ err = -EINVAL; ++ pr_err("no branches\n"); ++ goto out; ++ } ++ ++ if (au_opt_test(tmp, XINO)) ++ au_opt_set(sbinfo->si_mntflags, XINO); ++ opt = opts->opt; ++ while (!err && opt->type != Opt_tail) ++ err = au_opt_xino(sb, opt++, &opt_xino, opts); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_opts_verify(sb, sb->s_flags, tmp); ++ if (unlikely(err)) ++ goto out; ++ ++ /* restore xino */ ++ if (au_opt_test(tmp, XINO) && !opt_xino) { ++ xino.file = au_xino_def(sb); ++ err = PTR_ERR(xino.file); ++ if (IS_ERR(xino.file)) ++ goto out; ++ ++ err = au_xino_set(sb, &xino, /*remount*/0); ++ fput(xino.file); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ /* restore udba */ ++ tmp &= AuOptMask_UDBA; ++ sbinfo->si_mntflags &= ~AuOptMask_UDBA; ++ sbinfo->si_mntflags |= tmp; ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ err = au_hnotify_reset_br(tmp, br, br->br_perm); ++ if (unlikely(err)) ++ AuIOErr("hnotify failed on br %d, %d, ignored\n", ++ bindex, err); ++ /* go on even if err */ ++ } ++ if (au_opt_test(tmp, UDBA_HNOTIFY)) { ++ dir = d_inode(sb->s_root); ++ au_hn_reset(dir, au_hi_flags(dir, /*isdir*/1) & ~AuHi_XINO); ++ } ++ ++out: ++ return err; ++} ++ ++int au_opts_remount(struct super_block *sb, struct au_opts *opts) ++{ ++ int err, rerr; ++ unsigned char no_dreval; ++ struct inode *dir; ++ struct au_opt_xino *opt_xino; ++ struct au_opt *opt; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ err = au_dr_opt_flush(sb); ++ if (unlikely(err)) ++ goto out; ++ au_fset_opts(opts->flags, DR_FLUSHED); ++ ++ dir = d_inode(sb->s_root); ++ sbinfo = au_sbi(sb); ++ opt_xino = NULL; ++ opt = opts->opt; ++ while (err >= 0 && opt->type != Opt_tail) { ++ err = au_opt_simple(sb, opt, opts); ++ if (!err) ++ err = au_opt_br(sb, opt, opts); ++ if (!err) ++ err = au_opt_xino(sb, opt, &opt_xino, opts); ++ opt++; ++ } ++ if (err > 0) ++ err = 0; ++ AuTraceErr(err); ++ /* go on even err */ ++ ++ no_dreval = !!au_ftest_si(sbinfo, NO_DREVAL); ++ rerr = au_opts_verify(sb, opts->sb_flags, /*pending*/0); ++ if (unlikely(rerr && !err)) ++ err = rerr; ++ ++ if (no_dreval != !!au_ftest_si(sbinfo, NO_DREVAL)) ++ au_fset_opts(opts->flags, REFRESH_IDOP); ++ ++ if (au_ftest_opts(opts->flags, TRUNC_XIB)) { ++ rerr = au_xib_trunc(sb); ++ if (unlikely(rerr && !err)) ++ err = rerr; ++ } ++ ++ /* will be handled by the caller */ ++ if (!au_ftest_opts(opts->flags, REFRESH) ++ && (opts->given_udba ++ || au_opt_test(sbinfo->si_mntflags, XINO) ++ || au_ftest_opts(opts->flags, REFRESH_IDOP) ++ )) ++ au_fset_opts(opts->flags, REFRESH); ++ ++ AuDbg("status 0x%x\n", opts->flags); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++unsigned int au_opt_udba(struct super_block *sb) ++{ ++ return au_mntflags(sb) & AuOptMask_UDBA; ++} +diff -Naur null/fs/aufs/opts.h linux-5.15.36/fs/aufs/opts.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/opts.h 2022-05-10 16:51:39.875744219 +0300 +@@ -0,0 +1,263 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * mount options/flags ++ */ ++ ++#ifndef __AUFS_OPTS_H__ ++#define __AUFS_OPTS_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++ ++enum { ++ Opt_br, ++ Opt_add, Opt_del, Opt_mod, Opt_append, Opt_prepend, ++ Opt_idel, Opt_imod, ++ Opt_dirwh, Opt_rdcache, Opt_rdblk, Opt_rdhash, ++ Opt_xino, Opt_noxino, ++ Opt_trunc_xino, Opt_trunc_xino_v, ++ Opt_trunc_xino_path, Opt_itrunc_xino, ++ Opt_trunc_xib, ++ Opt_shwh, ++ Opt_plink, Opt_list_plink, ++ Opt_udba, ++ Opt_dio, ++ Opt_diropq, Opt_diropq_a, Opt_diropq_w, ++ Opt_warn_perm, ++ Opt_wbr_copyup, Opt_wbr_create, ++ Opt_fhsm_sec, ++ Opt_verbose, Opt_noverbose, ++ Opt_sum, Opt_wsum, ++ Opt_dirperm1, ++ Opt_dirren, ++ Opt_acl, ++ Opt_tail, Opt_ignore, Opt_ignore_silent, Opt_err ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* mount flags */ ++#define AuOpt_XINO 1 /* external inode number bitmap ++ and translation table */ ++#define AuOpt_TRUNC_XINO (1 << 1) /* truncate xino files */ ++#define AuOpt_UDBA_NONE (1 << 2) /* users direct branch access */ ++#define AuOpt_UDBA_REVAL (1 << 3) ++#define AuOpt_UDBA_HNOTIFY (1 << 4) ++#define AuOpt_SHWH (1 << 5) /* show whiteout */ ++#define AuOpt_PLINK (1 << 6) /* pseudo-link */ ++#define AuOpt_DIRPERM1 (1 << 7) /* ignore the lower dir's perm ++ bits */ ++#define AuOpt_ALWAYS_DIROPQ (1 << 9) /* policy to creating diropq */ ++#define AuOpt_SUM (1 << 10) /* summation for statfs(2) */ ++#define AuOpt_SUM_W (1 << 11) /* unimplemented */ ++#define AuOpt_WARN_PERM (1 << 12) /* warn when add-branch */ ++#define AuOpt_VERBOSE (1 << 13) /* print the cause of error */ ++#define AuOpt_DIO (1 << 14) /* direct io */ ++#define AuOpt_DIRREN (1 << 15) /* directory rename */ ++ ++#ifndef CONFIG_AUFS_HNOTIFY ++#undef AuOpt_UDBA_HNOTIFY ++#define AuOpt_UDBA_HNOTIFY 0 ++#endif ++#ifndef CONFIG_AUFS_DIRREN ++#undef AuOpt_DIRREN ++#define AuOpt_DIRREN 0 ++#endif ++#ifndef CONFIG_AUFS_SHWH ++#undef AuOpt_SHWH ++#define AuOpt_SHWH 0 ++#endif ++ ++#define AuOpt_Def (AuOpt_XINO \ ++ | AuOpt_UDBA_REVAL \ ++ | AuOpt_PLINK \ ++ /* | AuOpt_DIRPERM1 */ \ ++ | AuOpt_WARN_PERM) ++#define AuOptMask_UDBA (AuOpt_UDBA_NONE \ ++ | AuOpt_UDBA_REVAL \ ++ | AuOpt_UDBA_HNOTIFY) ++ ++#define AuOpt_LkupDirFlags (LOOKUP_FOLLOW | LOOKUP_DIRECTORY) ++ ++#define au_opt_test(flags, name) (flags & AuOpt_##name) ++#define au_opt_set(flags, name) do { \ ++ BUILD_BUG_ON(AuOpt_##name & AuOptMask_UDBA); \ ++ ((flags) |= AuOpt_##name); \ ++} while (0) ++#define au_opt_set_udba(flags, name) do { \ ++ (flags) &= ~AuOptMask_UDBA; \ ++ ((flags) |= AuOpt_##name); \ ++} while (0) ++#define au_opt_clr(flags, name) do { \ ++ ((flags) &= ~AuOpt_##name); \ ++} while (0) ++ ++static inline unsigned int au_opts_plink(unsigned int mntflags) ++{ ++#ifdef CONFIG_PROC_FS ++ return mntflags; ++#else ++ return mntflags & ~AuOpt_PLINK; ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policies to select one among multiple writable branches */ ++enum { ++ AuWbrCreate_TDP, /* top down parent */ ++ AuWbrCreate_RR, /* round robin */ ++ AuWbrCreate_MFS, /* most free space */ ++ AuWbrCreate_MFSV, /* mfs with seconds */ ++ AuWbrCreate_MFSRR, /* mfs then rr */ ++ AuWbrCreate_MFSRRV, /* mfs then rr with seconds */ ++ AuWbrCreate_TDMFS, /* top down regardless parent and mfs */ ++ AuWbrCreate_TDMFSV, /* top down regardless parent and mfs */ ++ AuWbrCreate_PMFS, /* parent and mfs */ ++ AuWbrCreate_PMFSV, /* parent and mfs with seconds */ ++ AuWbrCreate_PMFSRR, /* parent, mfs and round-robin */ ++ AuWbrCreate_PMFSRRV, /* plus seconds */ ++ ++ AuWbrCreate_Def = AuWbrCreate_TDP ++}; ++ ++enum { ++ AuWbrCopyup_TDP, /* top down parent */ ++ AuWbrCopyup_BUP, /* bottom up parent */ ++ AuWbrCopyup_BU, /* bottom up */ ++ ++ AuWbrCopyup_Def = AuWbrCopyup_TDP ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct file; ++ ++struct au_opt_add { ++ aufs_bindex_t bindex; ++ char *pathname; ++ int perm; ++ struct path path; ++}; ++ ++struct au_opt_del { ++ char *pathname; ++ struct path h_path; ++}; ++ ++struct au_opt_mod { ++ char *path; ++ int perm; ++ struct dentry *h_root; ++}; ++ ++struct au_opt_xino { ++ char *path; ++ struct file *file; ++}; ++ ++struct au_opt_xino_itrunc { ++ aufs_bindex_t bindex; ++}; ++ ++struct au_opt_wbr_create { ++ int wbr_create; ++ int mfs_second; ++ unsigned long long mfsrr_watermark; ++}; ++ ++struct au_opt { ++ int type; ++ union { ++ struct au_opt_xino xino; ++ struct au_opt_xino_itrunc xino_itrunc; ++ struct au_opt_add add; ++ struct au_opt_del del; ++ struct au_opt_mod mod; ++ int dirwh; ++ int rdcache; ++ unsigned int rdblk; ++ unsigned int rdhash; ++ int udba; ++ struct au_opt_wbr_create wbr_create; ++ int wbr_copyup; ++ unsigned int fhsm_second; ++ bool tf; /* generic flag, true or false */ ++ }; ++}; ++ ++/* opts flags */ ++#define AuOpts_REMOUNT 1 ++#define AuOpts_REFRESH (1 << 1) ++#define AuOpts_TRUNC_XIB (1 << 2) ++#define AuOpts_REFRESH_DYAOP (1 << 3) ++#define AuOpts_REFRESH_IDOP (1 << 4) ++#define AuOpts_DR_FLUSHED (1 << 5) ++#define au_ftest_opts(flags, name) ((flags) & AuOpts_##name) ++#define au_fset_opts(flags, name) \ ++ do { (flags) |= AuOpts_##name; } while (0) ++#define au_fclr_opts(flags, name) \ ++ do { (flags) &= ~AuOpts_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_DIRREN ++#undef AuOpts_DR_FLUSHED ++#define AuOpts_DR_FLUSHED 0 ++#endif ++ ++struct au_opts { ++ struct au_opt *opt; ++ int max_opt; ++ ++ unsigned int given_udba; ++ unsigned int flags; ++ unsigned long sb_flags; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* opts.c */ ++int au_br_perm_val(char *perm); ++void au_optstr_br_perm(au_br_perm_str_t *str, int perm); ++int au_udba_val(char *str); ++const char *au_optstr_udba(int udba); ++int au_wbr_create_val(char *str, struct au_opt_wbr_create *create); ++const char *au_optstr_wbr_create(int wbr_create); ++int au_wbr_copyup_val(char *str); ++const char *au_optstr_wbr_copyup(int wbr_copyup); ++ ++int au_opt_add(struct au_opt *opt, char *opt_str, unsigned long sb_flags, ++ aufs_bindex_t bindex); ++struct super_block; ++int au_opts_verify(struct super_block *sb, unsigned long sb_flags, ++ unsigned int pending); ++int au_opts_mount(struct super_block *sb, struct au_opts *opts); ++int au_opts_remount(struct super_block *sb, struct au_opts *opts); ++ ++unsigned int au_opt_udba(struct super_block *sb); ++ ++/* fsctx.c */ ++int aufs_fsctx_init(struct fs_context *fc); ++extern const struct fs_parameter_spec aufs_fsctx_paramspec[]; ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_OPTS_H__ */ +diff -Naur null/fs/aufs/plink.c linux-5.15.36/fs/aufs/plink.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/plink.c 2022-05-10 16:51:39.875744219 +0300 +@@ -0,0 +1,516 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * pseudo-link ++ */ ++ ++#include "aufs.h" ++ ++/* ++ * the pseudo-link maintenance mode. ++ * during a user process maintains the pseudo-links, ++ * prohibit adding a new plink and branch manipulation. ++ * ++ * Flags ++ * NOPLM: ++ * For entry functions which will handle plink, and i_mutex is already held ++ * in VFS. ++ * They cannot wait and should return an error at once. ++ * Callers has to check the error. ++ * NOPLMW: ++ * For entry functions which will handle plink, but i_mutex is not held ++ * in VFS. ++ * They can wait the plink maintenance mode to finish. ++ * ++ * They behave like F_SETLK and F_SETLKW. ++ * If the caller never handle plink, then both flags are unnecessary. ++ */ ++ ++int au_plink_maint(struct super_block *sb, int flags) ++{ ++ int err; ++ pid_t pid, ppid; ++ struct task_struct *parent, *prev; ++ struct au_sbinfo *sbi; ++ ++ SiMustAnyLock(sb); ++ ++ err = 0; ++ if (!au_opt_test(au_mntflags(sb), PLINK)) ++ goto out; ++ ++ sbi = au_sbi(sb); ++ pid = sbi->si_plink_maint_pid; ++ if (!pid || pid == current->pid) ++ goto out; ++ ++ /* todo: it highly depends upon /sbin/mount.aufs */ ++ prev = NULL; ++ parent = current; ++ ppid = 0; ++ rcu_read_lock(); ++ while (1) { ++ parent = rcu_dereference(parent->real_parent); ++ if (parent == prev) ++ break; ++ ppid = task_pid_vnr(parent); ++ if (pid == ppid) { ++ rcu_read_unlock(); ++ goto out; ++ } ++ prev = parent; ++ } ++ rcu_read_unlock(); ++ ++ if (au_ftest_lock(flags, NOPLMW)) { ++ /* if there is no i_mutex lock in VFS, we don't need to wait */ ++ /* AuDebugOn(!lockdep_depth(current)); */ ++ while (sbi->si_plink_maint_pid) { ++ si_read_unlock(sb); ++ /* gave up wake_up_bit() */ ++ wait_event(sbi->si_plink_wq, !sbi->si_plink_maint_pid); ++ ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&sbi->si_nowait); ++ si_noflush_read_lock(sb); ++ } ++ } else if (au_ftest_lock(flags, NOPLM)) { ++ AuDbg("ppid %d, pid %d\n", ppid, pid); ++ err = -EAGAIN; ++ } ++ ++out: ++ return err; ++} ++ ++void au_plink_maint_leave(struct au_sbinfo *sbinfo) ++{ ++ spin_lock(&sbinfo->si_plink_maint_lock); ++ sbinfo->si_plink_maint_pid = 0; ++ spin_unlock(&sbinfo->si_plink_maint_lock); ++ wake_up_all(&sbinfo->si_plink_wq); ++} ++ ++int au_plink_maint_enter(struct super_block *sb) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ /* make sure i am the only one in this fs */ ++ si_write_lock(sb, AuLock_FLUSH); ++ if (au_opt_test(au_mntflags(sb), PLINK)) { ++ spin_lock(&sbinfo->si_plink_maint_lock); ++ if (!sbinfo->si_plink_maint_pid) ++ sbinfo->si_plink_maint_pid = current->pid; ++ else ++ err = -EBUSY; ++ spin_unlock(&sbinfo->si_plink_maint_lock); ++ } ++ si_write_unlock(sb); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_DEBUG ++void au_plink_list(struct super_block *sb) ++{ ++ int i; ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_icntnr *icntnr; ++ ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); ++ ++ for (i = 0; i < AuPlink_NHASH; i++) { ++ hbl = sbinfo->si_plink + i; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(icntnr, pos, hbl, plink) ++ AuDbg("%lu\n", icntnr->vfs_inode.i_ino); ++ hlist_bl_unlock(hbl); ++ } ++} ++#endif ++ ++/* is the inode pseudo-linked? */ ++int au_plink_test(struct inode *inode) ++{ ++ int found, i; ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_icntnr *icntnr; ++ ++ sbinfo = au_sbi(inode->i_sb); ++ AuRwMustAnyLock(&sbinfo->si_rwsem); ++ AuDebugOn(!au_opt_test(au_mntflags(inode->i_sb), PLINK)); ++ AuDebugOn(au_plink_maint(inode->i_sb, AuLock_NOPLM)); ++ ++ found = 0; ++ i = au_plink_hash(inode->i_ino); ++ hbl = sbinfo->si_plink + i; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(icntnr, pos, hbl, plink) ++ if (&icntnr->vfs_inode == inode) { ++ found = 1; ++ break; ++ } ++ hlist_bl_unlock(hbl); ++ return found; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * generate a name for plink. ++ * the file will be stored under AUFS_WH_PLINKDIR. ++ */ ++/* 20 is max digits length of ulong 64 */ ++#define PLINK_NAME_LEN ((20 + 1) * 2) ++ ++static int plink_name(char *name, int len, struct inode *inode, ++ aufs_bindex_t bindex) ++{ ++ int rlen; ++ struct inode *h_inode; ++ ++ h_inode = au_h_iptr(inode, bindex); ++ rlen = snprintf(name, len, "%lu.%lu", inode->i_ino, h_inode->i_ino); ++ return rlen; ++} ++ ++struct au_do_plink_lkup_args { ++ struct dentry **errp; ++ struct qstr *tgtname; ++ struct path *h_ppath; ++}; ++ ++static struct dentry *au_do_plink_lkup(struct qstr *tgtname, ++ struct path *h_ppath) ++{ ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ ++ h_inode = d_inode(h_ppath->dentry); ++ inode_lock_shared_nested(h_inode, AuLsc_I_CHILD2); ++ h_dentry = vfsub_lkup_one(tgtname, h_ppath); ++ inode_unlock_shared(h_inode); ++ ++ return h_dentry; ++} ++ ++static void au_call_do_plink_lkup(void *args) ++{ ++ struct au_do_plink_lkup_args *a = args; ++ *a->errp = au_do_plink_lkup(a->tgtname, a->h_ppath); ++} ++ ++/* lookup the plink-ed @inode under the branch at @bindex */ ++struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex) ++{ ++ struct dentry *h_dentry; ++ struct au_branch *br; ++ struct path h_ppath; ++ int wkq_err; ++ char a[PLINK_NAME_LEN]; ++ struct qstr tgtname = QSTR_INIT(a, 0); ++ ++ AuDebugOn(au_plink_maint(inode->i_sb, AuLock_NOPLM)); ++ ++ br = au_sbr(inode->i_sb, bindex); ++ h_ppath.dentry = br->br_wbr->wbr_plink; ++ h_ppath.mnt = au_br_mnt(br); ++ tgtname.len = plink_name(a, sizeof(a), inode, bindex); ++ ++ if (!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) { ++ struct au_do_plink_lkup_args args = { ++ .errp = &h_dentry, ++ .tgtname = &tgtname, ++ .h_ppath = &h_ppath ++ }; ++ ++ wkq_err = au_wkq_wait(au_call_do_plink_lkup, &args); ++ if (unlikely(wkq_err)) ++ h_dentry = ERR_PTR(wkq_err); ++ } else ++ h_dentry = au_do_plink_lkup(&tgtname, &h_ppath); ++ ++ return h_dentry; ++} ++ ++/* create a pseudo-link */ ++static int do_whplink(struct qstr *tgt, struct path *h_ppath, ++ struct dentry *h_dentry) ++{ ++ int err; ++ struct path h_path; ++ struct inode *h_dir, *delegated; ++ ++ h_dir = d_inode(h_ppath->dentry); ++ inode_lock_nested(h_dir, AuLsc_I_CHILD2); ++ h_path.mnt = h_ppath->mnt; ++again: ++ h_path.dentry = vfsub_lkup_one(tgt, h_ppath); ++ err = PTR_ERR(h_path.dentry); ++ if (IS_ERR(h_path.dentry)) ++ goto out; ++ ++ err = 0; ++ /* wh.plink dir is not monitored */ ++ /* todo: is it really safe? */ ++ if (d_is_positive(h_path.dentry) ++ && d_inode(h_path.dentry) != d_inode(h_dentry)) { ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, &h_path, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ dput(h_path.dentry); ++ h_path.dentry = NULL; ++ if (!err) ++ goto again; ++ } ++ if (!err && d_is_negative(h_path.dentry)) { ++ delegated = NULL; ++ err = vfsub_link(h_dentry, h_dir, &h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ } ++ dput(h_path.dentry); ++ ++out: ++ inode_unlock(h_dir); ++ return err; ++} ++ ++struct do_whplink_args { ++ int *errp; ++ struct qstr *tgt; ++ struct path *h_ppath; ++ struct dentry *h_dentry; ++}; ++ ++static void call_do_whplink(void *args) ++{ ++ struct do_whplink_args *a = args; ++ *a->errp = do_whplink(a->tgt, a->h_ppath, a->h_dentry); ++} ++ ++static int whplink(struct dentry *h_dentry, struct inode *inode, ++ aufs_bindex_t bindex) ++{ ++ int err, wkq_err; ++ struct au_branch *br; ++ struct au_wbr *wbr; ++ struct path h_ppath; ++ char a[PLINK_NAME_LEN]; ++ struct qstr tgtname = QSTR_INIT(a, 0); ++ ++ br = au_sbr(inode->i_sb, bindex); ++ wbr = br->br_wbr; ++ h_ppath.dentry = wbr->wbr_plink; ++ h_ppath.mnt = au_br_mnt(br); ++ tgtname.len = plink_name(a, sizeof(a), inode, bindex); ++ ++ /* always superio. */ ++ if (!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) { ++ struct do_whplink_args args = { ++ .errp = &err, ++ .tgt = &tgtname, ++ .h_ppath = &h_ppath, ++ .h_dentry = h_dentry ++ }; ++ wkq_err = au_wkq_wait(call_do_whplink, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } else ++ err = do_whplink(&tgtname, &h_ppath, h_dentry); ++ ++ return err; ++} ++ ++/* ++ * create a new pseudo-link for @h_dentry on @bindex. ++ * the linked inode is held in aufs @inode. ++ */ ++void au_plink_append(struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_dentry) ++{ ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_icntnr *icntnr; ++ int found, err, cnt, i; ++ ++ sb = inode->i_sb; ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); ++ ++ found = au_plink_test(inode); ++ if (found) ++ return; ++ ++ i = au_plink_hash(inode->i_ino); ++ hbl = sbinfo->si_plink + i; ++ au_igrab(inode); ++ ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(icntnr, pos, hbl, plink) { ++ if (&icntnr->vfs_inode == inode) { ++ found = 1; ++ break; ++ } ++ } ++ if (!found) { ++ icntnr = container_of(inode, struct au_icntnr, vfs_inode); ++ hlist_bl_add_head(&icntnr->plink, hbl); ++ } ++ hlist_bl_unlock(hbl); ++ if (!found) { ++ cnt = au_hbl_count(hbl); ++#define msg "unexpectedly unbalanced or too many pseudo-links" ++ if (cnt > AUFS_PLINK_WARN) ++ AuWarn1(msg ", %d\n", cnt); ++#undef msg ++ err = whplink(h_dentry, inode, bindex); ++ if (unlikely(err)) { ++ pr_warn("err %d, damaged pseudo link.\n", err); ++ au_hbl_del(&icntnr->plink, hbl); ++ iput(&icntnr->vfs_inode); ++ } ++ } else ++ iput(&icntnr->vfs_inode); ++} ++ ++/* free all plinks */ ++void au_plink_put(struct super_block *sb, int verbose) ++{ ++ int i, warned; ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos, *tmp; ++ struct au_icntnr *icntnr; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); ++ ++ /* no spin_lock since sbinfo is write-locked */ ++ warned = 0; ++ for (i = 0; i < AuPlink_NHASH; i++) { ++ hbl = sbinfo->si_plink + i; ++ if (!warned && verbose && !hlist_bl_empty(hbl)) { ++ pr_warn("pseudo-link is not flushed"); ++ warned = 1; ++ } ++ hlist_bl_for_each_entry_safe(icntnr, pos, tmp, hbl, plink) ++ iput(&icntnr->vfs_inode); ++ INIT_HLIST_BL_HEAD(hbl); ++ } ++} ++ ++void au_plink_clean(struct super_block *sb, int verbose) ++{ ++ struct dentry *root; ++ ++ root = sb->s_root; ++ aufs_write_lock(root); ++ if (au_opt_test(au_mntflags(sb), PLINK)) ++ au_plink_put(sb, verbose); ++ aufs_write_unlock(root); ++} ++ ++static int au_plink_do_half_refresh(struct inode *inode, aufs_bindex_t br_id) ++{ ++ int do_put; ++ aufs_bindex_t btop, bbot, bindex; ++ ++ do_put = 0; ++ btop = au_ibtop(inode); ++ bbot = au_ibbot(inode); ++ if (btop >= 0) { ++ for (bindex = btop; bindex <= bbot; bindex++) { ++ if (!au_h_iptr(inode, bindex) ++ || au_ii_br_id(inode, bindex) != br_id) ++ continue; ++ au_set_h_iptr(inode, bindex, NULL, 0); ++ do_put = 1; ++ break; ++ } ++ if (do_put) ++ for (bindex = btop; bindex <= bbot; bindex++) ++ if (au_h_iptr(inode, bindex)) { ++ do_put = 0; ++ break; ++ } ++ } else ++ do_put = 1; ++ ++ return do_put; ++} ++ ++/* free the plinks on a branch specified by @br_id */ ++void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id) ++{ ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos, *tmp; ++ struct au_icntnr *icntnr; ++ struct inode *inode; ++ int i, do_put; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); ++ ++ /* no bit_lock since sbinfo is write-locked */ ++ for (i = 0; i < AuPlink_NHASH; i++) { ++ hbl = sbinfo->si_plink + i; ++ hlist_bl_for_each_entry_safe(icntnr, pos, tmp, hbl, plink) { ++ inode = au_igrab(&icntnr->vfs_inode); ++ ii_write_lock_child(inode); ++ do_put = au_plink_do_half_refresh(inode, br_id); ++ if (do_put) { ++ hlist_bl_del(&icntnr->plink); ++ iput(inode); ++ } ++ ii_write_unlock(inode); ++ iput(inode); ++ } ++ } ++} +diff -Naur null/fs/aufs/poll.c linux-5.15.36/fs/aufs/poll.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/poll.c 2022-05-10 16:51:39.875744219 +0300 +@@ -0,0 +1,51 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * poll operation ++ * There is only one filesystem which implements ->poll operation, currently. ++ */ ++ ++#include "aufs.h" ++ ++__poll_t aufs_poll(struct file *file, struct poll_table_struct *pt) ++{ ++ __poll_t mask; ++ struct file *h_file; ++ struct super_block *sb; ++ ++ /* We should pretend an error happened. */ ++ mask = EPOLLERR /* | EPOLLIN | EPOLLOUT */; ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/0, /*lsc*/0); ++ if (IS_ERR(h_file)) { ++ AuDbg("h_file %ld\n", PTR_ERR(h_file)); ++ goto out; ++ } ++ ++ mask = vfs_poll(h_file, pt); ++ fput(h_file); /* instead of au_read_post() */ ++ ++out: ++ si_read_unlock(sb); ++ if (mask & EPOLLERR) ++ AuDbg("mask 0x%x\n", mask); ++ return mask; ++} +diff -Naur null/fs/aufs/posix_acl.c linux-5.15.36/fs/aufs/posix_acl.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/posix_acl.c 2022-05-10 16:51:39.875744219 +0300 +@@ -0,0 +1,111 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2014-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * posix acl operations ++ */ ++ ++#include ++#include "aufs.h" ++ ++struct posix_acl *aufs_get_acl(struct inode *inode, int type, bool rcu) ++{ ++ struct posix_acl *acl; ++ int err; ++ aufs_bindex_t bindex; ++ struct inode *h_inode; ++ struct super_block *sb; ++ ++ acl = ERR_PTR(-ECHILD); ++ if (rcu) ++ goto out; ++ ++ acl = NULL; ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ ii_read_lock_child(inode); ++ if (!(sb->s_flags & SB_POSIXACL)) ++ goto unlock; ++ ++ bindex = au_ibtop(inode); ++ h_inode = au_h_iptr(inode, bindex); ++ if (unlikely(!h_inode ++ || ((h_inode->i_mode & S_IFMT) ++ != (inode->i_mode & S_IFMT)))) { ++ err = au_busy_or_stale(); ++ acl = ERR_PTR(err); ++ goto unlock; ++ } ++ ++ /* always topmost only */ ++ acl = get_acl(h_inode, type); ++ if (IS_ERR(acl)) ++ forget_cached_acl(inode, type); ++ else ++ set_cached_acl(inode, type, acl); ++ ++unlock: ++ ii_read_unlock(inode); ++ si_read_unlock(sb); ++ ++out: ++ AuTraceErrPtr(acl); ++ return acl; ++} ++ ++int aufs_set_acl(struct user_namespace *userns, struct inode *inode, ++ struct posix_acl *acl, int type) ++{ ++ int err; ++ ssize_t ssz; ++ struct dentry *dentry; ++ struct au_sxattr arg = { ++ .type = AU_ACL_SET, ++ .u.acl_set = { ++ .acl = acl, ++ .type = type ++ }, ++ }; ++ ++ IMustLock(inode); ++ ++ if (inode->i_ino == AUFS_ROOT_INO) ++ dentry = dget(inode->i_sb->s_root); ++ else { ++ dentry = d_find_alias(inode); ++ if (!dentry) ++ dentry = d_find_any_alias(inode); ++ if (!dentry) { ++ pr_warn("cannot handle this inode, " ++ "please report to aufs-users ML\n"); ++ err = -ENOENT; ++ goto out; ++ } ++ } ++ ++ ssz = au_sxattr(dentry, inode, &arg); ++ /* forget even it if succeeds since the branch might set differently */ ++ forget_cached_acl(inode, type); ++ dput(dentry); ++ err = ssz; ++ if (ssz >= 0) ++ err = 0; ++ ++out: ++ return err; ++} +diff -Naur null/fs/aufs/procfs.c linux-5.15.36/fs/aufs/procfs.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/procfs.c 2022-05-10 16:51:39.875744219 +0300 +@@ -0,0 +1,170 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2010-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * procfs interfaces ++ */ ++ ++#include ++#include "aufs.h" ++ ++static int au_procfs_plm_release(struct inode *inode, struct file *file) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ sbinfo = file->private_data; ++ if (sbinfo) { ++ au_plink_maint_leave(sbinfo); ++ kobject_put(&sbinfo->si_kobj); ++ } ++ ++ return 0; ++} ++ ++static void au_procfs_plm_write_clean(struct file *file) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ sbinfo = file->private_data; ++ if (sbinfo) ++ au_plink_clean(sbinfo->si_sb, /*verbose*/0); ++} ++ ++static int au_procfs_plm_write_si(struct file *file, unsigned long id) ++{ ++ int err; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_node *pos; ++ ++ err = -EBUSY; ++ if (unlikely(file->private_data)) ++ goto out; ++ ++ sb = NULL; ++ /* don't use au_sbilist_lock() here */ ++ hlist_bl_lock(&au_sbilist); ++ hlist_bl_for_each_entry(sbinfo, pos, &au_sbilist, si_list) ++ if (id == sysaufs_si_id(sbinfo)) { ++ if (kobject_get_unless_zero(&sbinfo->si_kobj)) ++ sb = sbinfo->si_sb; ++ break; ++ } ++ hlist_bl_unlock(&au_sbilist); ++ ++ err = -EINVAL; ++ if (unlikely(!sb)) ++ goto out; ++ ++ err = au_plink_maint_enter(sb); ++ if (!err) ++ /* keep kobject_get() */ ++ file->private_data = sbinfo; ++ else ++ kobject_put(&sbinfo->si_kobj); ++out: ++ return err; ++} ++ ++/* ++ * Accept a valid "si=xxxx" only. ++ * Once it is accepted successfully, accept "clean" too. ++ */ ++static ssize_t au_procfs_plm_write(struct file *file, const char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ ssize_t err; ++ unsigned long id; ++ /* last newline is allowed */ ++ char buf[3 + sizeof(unsigned long) * 2 + 1]; ++ ++ err = -EACCES; ++ if (unlikely(!capable(CAP_SYS_ADMIN))) ++ goto out; ++ ++ err = -EINVAL; ++ if (unlikely(count > sizeof(buf))) ++ goto out; ++ ++ err = copy_from_user(buf, ubuf, count); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ goto out; ++ } ++ buf[count] = 0; ++ ++ err = -EINVAL; ++ if (!strcmp("clean", buf)) { ++ au_procfs_plm_write_clean(file); ++ goto out_success; ++ } else if (unlikely(strncmp("si=", buf, 3))) ++ goto out; ++ ++ err = kstrtoul(buf + 3, 16, &id); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_procfs_plm_write_si(file, id); ++ if (unlikely(err)) ++ goto out; ++ ++out_success: ++ err = count; /* success */ ++out: ++ return err; ++} ++ ++static const struct proc_ops au_procfs_plm_op = { ++ .proc_write = au_procfs_plm_write, ++ .proc_release = au_procfs_plm_release ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct proc_dir_entry *au_procfs_dir; ++ ++void au_procfs_fin(void) ++{ ++ remove_proc_entry(AUFS_PLINK_MAINT_NAME, au_procfs_dir); ++ remove_proc_entry(AUFS_PLINK_MAINT_DIR, NULL); ++} ++ ++int __init au_procfs_init(void) ++{ ++ int err; ++ struct proc_dir_entry *entry; ++ ++ err = -ENOMEM; ++ au_procfs_dir = proc_mkdir(AUFS_PLINK_MAINT_DIR, NULL); ++ if (unlikely(!au_procfs_dir)) ++ goto out; ++ ++ entry = proc_create(AUFS_PLINK_MAINT_NAME, S_IFREG | 0200, ++ au_procfs_dir, &au_procfs_plm_op); ++ if (unlikely(!entry)) ++ goto out_dir; ++ ++ err = 0; ++ goto out; /* success */ ++ ++ ++out_dir: ++ remove_proc_entry(AUFS_PLINK_MAINT_DIR, NULL); ++out: ++ return err; ++} +diff -Naur null/fs/aufs/rdu.c linux-5.15.36/fs/aufs/rdu.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/rdu.c 2022-05-10 16:51:39.876744219 +0300 +@@ -0,0 +1,384 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * readdir in userspace. ++ */ ++ ++#include ++#include ++#include ++#include "aufs.h" ++ ++/* bits for struct aufs_rdu.flags */ ++#define AuRdu_CALLED 1 ++#define AuRdu_CONT (1 << 1) ++#define AuRdu_FULL (1 << 2) ++#define au_ftest_rdu(flags, name) ((flags) & AuRdu_##name) ++#define au_fset_rdu(flags, name) \ ++ do { (flags) |= AuRdu_##name; } while (0) ++#define au_fclr_rdu(flags, name) \ ++ do { (flags) &= ~AuRdu_##name; } while (0) ++ ++struct au_rdu_arg { ++ struct dir_context ctx; ++ struct aufs_rdu *rdu; ++ union au_rdu_ent_ul ent; ++ unsigned long end; ++ ++ struct super_block *sb; ++ int err; ++}; ++ ++static int au_rdu_fill(struct dir_context *ctx, const char *name, int nlen, ++ loff_t offset, u64 h_ino, unsigned int d_type) ++{ ++ int err, len; ++ struct au_rdu_arg *arg = container_of(ctx, struct au_rdu_arg, ctx); ++ struct aufs_rdu *rdu = arg->rdu; ++ struct au_rdu_ent ent; ++ ++ err = 0; ++ arg->err = 0; ++ au_fset_rdu(rdu->cookie.flags, CALLED); ++ len = au_rdu_len(nlen); ++ if (arg->ent.ul + len < arg->end) { ++ ent.ino = h_ino; ++ ent.bindex = rdu->cookie.bindex; ++ ent.type = d_type; ++ ent.nlen = nlen; ++ if (unlikely(nlen > AUFS_MAX_NAMELEN)) ++ ent.type = DT_UNKNOWN; ++ ++ /* unnecessary to support mmap_sem since this is a dir */ ++ err = -EFAULT; ++ if (copy_to_user(arg->ent.e, &ent, sizeof(ent))) ++ goto out; ++ if (copy_to_user(arg->ent.e->name, name, nlen)) ++ goto out; ++ /* the terminating NULL */ ++ if (__put_user(0, arg->ent.e->name + nlen)) ++ goto out; ++ err = 0; ++ /* AuDbg("%p, %.*s\n", arg->ent.p, nlen, name); */ ++ arg->ent.ul += len; ++ rdu->rent++; ++ } else { ++ err = -EFAULT; ++ au_fset_rdu(rdu->cookie.flags, FULL); ++ rdu->full = 1; ++ rdu->tail = arg->ent; ++ } ++ ++out: ++ /* AuTraceErr(err); */ ++ return err; ++} ++ ++static int au_rdu_do(struct file *h_file, struct au_rdu_arg *arg) ++{ ++ int err; ++ loff_t offset; ++ struct au_rdu_cookie *cookie = &arg->rdu->cookie; ++ ++ /* we don't have to care (FMODE_32BITHASH | FMODE_64BITHASH) for ext4 */ ++ offset = vfsub_llseek(h_file, cookie->h_pos, SEEK_SET); ++ err = offset; ++ if (unlikely(offset != cookie->h_pos)) ++ goto out; ++ ++ err = 0; ++ do { ++ arg->err = 0; ++ au_fclr_rdu(cookie->flags, CALLED); ++ /* smp_mb(); */ ++ err = vfsub_iterate_dir(h_file, &arg->ctx); ++ if (err >= 0) ++ err = arg->err; ++ } while (!err ++ && au_ftest_rdu(cookie->flags, CALLED) ++ && !au_ftest_rdu(cookie->flags, FULL)); ++ cookie->h_pos = h_file->f_pos; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_rdu(struct file *file, struct aufs_rdu *rdu) ++{ ++ int err; ++ aufs_bindex_t bbot; ++ struct au_rdu_arg arg = { ++ .ctx = { ++ .actor = au_rdu_fill ++ } ++ }; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct file *h_file; ++ struct au_rdu_cookie *cookie = &rdu->cookie; ++ ++ /* VERIFY_WRITE */ ++ err = !access_ok(rdu->ent.e, rdu->sz); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out; ++ } ++ rdu->rent = 0; ++ rdu->tail = rdu->ent; ++ rdu->full = 0; ++ arg.rdu = rdu; ++ arg.ent = rdu->ent; ++ arg.end = arg.ent.ul; ++ arg.end += rdu->sz; ++ ++ err = -ENOTDIR; ++ if (unlikely(!file->f_op->iterate && !file->f_op->iterate_shared)) ++ goto out; ++ ++ err = security_file_permission(file, MAY_READ); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out; ++ ++ dentry = file->f_path.dentry; ++ inode = d_inode(dentry); ++ inode_lock_shared(inode); ++ ++ arg.sb = inode->i_sb; ++ err = si_read_lock(arg.sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out_mtx; ++ err = au_alive_dir(dentry); ++ if (unlikely(err)) ++ goto out_si; ++ /* todo: reval? */ ++ fi_read_lock(file); ++ ++ err = -EAGAIN; ++ if (unlikely(au_ftest_rdu(cookie->flags, CONT) ++ && cookie->generation != au_figen(file))) ++ goto out_unlock; ++ ++ err = 0; ++ if (!rdu->blk) { ++ rdu->blk = au_sbi(arg.sb)->si_rdblk; ++ if (!rdu->blk) ++ rdu->blk = au_dir_size(file, /*dentry*/NULL); ++ } ++ bbot = au_fbtop(file); ++ if (cookie->bindex < bbot) ++ cookie->bindex = bbot; ++ bbot = au_fbbot_dir(file); ++ /* AuDbg("b%d, b%d\n", cookie->bindex, bbot); */ ++ for (; !err && cookie->bindex <= bbot; ++ cookie->bindex++, cookie->h_pos = 0) { ++ h_file = au_hf_dir(file, cookie->bindex); ++ if (!h_file) ++ continue; ++ ++ au_fclr_rdu(cookie->flags, FULL); ++ err = au_rdu_do(h_file, &arg); ++ AuTraceErr(err); ++ if (unlikely(au_ftest_rdu(cookie->flags, FULL) || err)) ++ break; ++ } ++ AuDbg("rent %llu\n", rdu->rent); ++ ++ if (!err && !au_ftest_rdu(cookie->flags, CONT)) { ++ rdu->shwh = !!au_opt_test(au_sbi(arg.sb)->si_mntflags, SHWH); ++ au_fset_rdu(cookie->flags, CONT); ++ cookie->generation = au_figen(file); ++ } ++ ++ ii_read_lock_child(inode); ++ fsstack_copy_attr_atime(inode, au_h_iptr(inode, au_ibtop(inode))); ++ ii_read_unlock(inode); ++ ++out_unlock: ++ fi_read_unlock(file); ++out_si: ++ si_read_unlock(arg.sb); ++out_mtx: ++ inode_unlock_shared(inode); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_rdu_ino(struct file *file, struct aufs_rdu *rdu) ++{ ++ int err; ++ ino_t ino; ++ unsigned long long nent; ++ union au_rdu_ent_ul *u; ++ struct au_rdu_ent ent; ++ struct super_block *sb; ++ ++ err = 0; ++ nent = rdu->nent; ++ u = &rdu->ent; ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ while (nent-- > 0) { ++ /* unnecessary to support mmap_sem since this is a dir */ ++ err = copy_from_user(&ent, u->e, sizeof(ent)); ++ if (!err) ++ /* VERIFY_WRITE */ ++ err = !access_ok(&u->e->ino, sizeof(ino)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ break; ++ } ++ ++ /* AuDbg("b%d, i%llu\n", ent.bindex, ent.ino); */ ++ if (!ent.wh) ++ err = au_ino(sb, ent.bindex, ent.ino, ent.type, &ino); ++ else ++ err = au_wh_ino(sb, ent.bindex, ent.ino, ent.type, ++ &ino); ++ if (unlikely(err)) { ++ AuTraceErr(err); ++ break; ++ } ++ ++ err = __put_user(ino, &u->e->ino); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ break; ++ } ++ u->ul += au_rdu_len(ent.nlen); ++ } ++ si_read_unlock(sb); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_rdu_verify(struct aufs_rdu *rdu) ++{ ++ AuDbg("rdu{%llu, %p, %u | %u | %llu, %u, %u | " ++ "%llu, b%d, 0x%x, g%u}\n", ++ rdu->sz, rdu->ent.e, rdu->verify[AufsCtlRduV_SZ], ++ rdu->blk, ++ rdu->rent, rdu->shwh, rdu->full, ++ rdu->cookie.h_pos, rdu->cookie.bindex, rdu->cookie.flags, ++ rdu->cookie.generation); ++ ++ if (rdu->verify[AufsCtlRduV_SZ] == sizeof(*rdu)) ++ return 0; ++ ++ AuDbg("%u:%u\n", ++ rdu->verify[AufsCtlRduV_SZ], (unsigned int)sizeof(*rdu)); ++ return -EINVAL; ++} ++ ++long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ long err, e; ++ struct aufs_rdu rdu; ++ void __user *p = (void __user *)arg; ++ ++ err = copy_from_user(&rdu, p, sizeof(rdu)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out; ++ } ++ err = au_rdu_verify(&rdu); ++ if (unlikely(err)) ++ goto out; ++ ++ switch (cmd) { ++ case AUFS_CTL_RDU: ++ err = au_rdu(file, &rdu); ++ if (unlikely(err)) ++ break; ++ ++ e = copy_to_user(p, &rdu, sizeof(rdu)); ++ if (unlikely(e)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ } ++ break; ++ case AUFS_CTL_RDU_INO: ++ err = au_rdu_ino(file, &rdu); ++ break; ++ ++ default: ++ /* err = -ENOTTY; */ ++ err = -EINVAL; ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++#ifdef CONFIG_COMPAT ++long au_rdu_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ long err, e; ++ struct aufs_rdu rdu; ++ void __user *p = compat_ptr(arg); ++ ++ /* todo: get_user()? */ ++ err = copy_from_user(&rdu, p, sizeof(rdu)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out; ++ } ++ rdu.ent.e = compat_ptr(rdu.ent.ul); ++ err = au_rdu_verify(&rdu); ++ if (unlikely(err)) ++ goto out; ++ ++ switch (cmd) { ++ case AUFS_CTL_RDU: ++ err = au_rdu(file, &rdu); ++ if (unlikely(err)) ++ break; ++ ++ rdu.ent.ul = ptr_to_compat(rdu.ent.e); ++ rdu.tail.ul = ptr_to_compat(rdu.tail.e); ++ e = copy_to_user(p, &rdu, sizeof(rdu)); ++ if (unlikely(e)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ } ++ break; ++ case AUFS_CTL_RDU_INO: ++ err = au_rdu_ino(file, &rdu); ++ break; ++ ++ default: ++ /* err = -ENOTTY; */ ++ err = -EINVAL; ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++#endif +diff -Naur null/fs/aufs/rwsem.h linux-5.15.36/fs/aufs/rwsem.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/rwsem.h 2022-05-10 16:51:39.876744219 +0300 +@@ -0,0 +1,85 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * simple read-write semaphore wrappers ++ */ ++ ++#ifndef __AUFS_RWSEM_H__ ++#define __AUFS_RWSEM_H__ ++ ++#ifdef __KERNEL__ ++ ++#include "debug.h" ++ ++/* in the future, the name 'au_rwsem' will be totally gone */ ++#define au_rwsem rw_semaphore ++ ++/* to debug easier, do not make them inlined functions */ ++#define AuRwMustNoWaiters(rw) AuDebugOn(rwsem_is_contended(rw)) ++ ++#ifdef CONFIG_LOCKDEP ++/* rwsem_is_locked() is unusable */ ++#define AuRwMustReadLock(rw) AuDebugOn(IS_ENABLED(CONFIG_LOCKDEP) \ ++ && !lockdep_recursing(current) \ ++ && debug_locks \ ++ && !lockdep_is_held_type(rw, 1)) ++#define AuRwMustWriteLock(rw) AuDebugOn(IS_ENABLED(CONFIG_LOCKDEP) \ ++ && !lockdep_recursing(current) \ ++ && debug_locks \ ++ && !lockdep_is_held_type(rw, 0)) ++#define AuRwMustAnyLock(rw) AuDebugOn(IS_ENABLED(CONFIG_LOCKDEP) \ ++ && !lockdep_recursing(current) \ ++ && debug_locks \ ++ && !lockdep_is_held(rw)) ++#define AuRwDestroy(rw) AuDebugOn(IS_ENABLED(CONFIG_LOCKDEP) \ ++ && !lockdep_recursing(current) \ ++ && debug_locks \ ++ && lockdep_is_held(rw)) ++#else ++#define AuRwMustReadLock(rw) do {} while (0) ++#define AuRwMustWriteLock(rw) do {} while (0) ++#define AuRwMustAnyLock(rw) do {} while (0) ++#define AuRwDestroy(rw) do {} while (0) ++#endif ++ ++#define au_rw_init(rw) init_rwsem(rw) ++ ++#define au_rw_init_wlock(rw) do { \ ++ au_rw_init(rw); \ ++ down_write(rw); \ ++ } while (0) ++ ++#define au_rw_init_wlock_nested(rw, lsc) do { \ ++ au_rw_init(rw); \ ++ down_write_nested(rw, lsc); \ ++ } while (0) ++ ++#define au_rw_read_lock(rw) down_read(rw) ++#define au_rw_read_lock_nested(rw, lsc) down_read_nested(rw, lsc) ++#define au_rw_read_unlock(rw) up_read(rw) ++#define au_rw_dgrade_lock(rw) downgrade_write(rw) ++#define au_rw_write_lock(rw) down_write(rw) ++#define au_rw_write_lock_nested(rw, lsc) down_write_nested(rw, lsc) ++#define au_rw_write_unlock(rw) up_write(rw) ++/* why is not _nested version defined? */ ++#define au_rw_read_trylock(rw) down_read_trylock(rw) ++#define au_rw_write_trylock(rw) down_write_trylock(rw) ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_RWSEM_H__ */ +diff -Naur null/fs/aufs/sbinfo.c linux-5.15.36/fs/aufs/sbinfo.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/sbinfo.c 2022-05-10 16:51:39.876744219 +0300 +@@ -0,0 +1,316 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * superblock private data ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* ++ * they are necessary regardless sysfs is disabled. ++ */ ++void au_si_free(struct kobject *kobj) ++{ ++ int i; ++ struct au_sbinfo *sbinfo; ++ char *locked __maybe_unused; /* debug only */ ++ ++ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); ++ for (i = 0; i < AuPlink_NHASH; i++) ++ AuDebugOn(!hlist_bl_empty(sbinfo->si_plink + i)); ++ AuDebugOn(atomic_read(&sbinfo->si_nowait.nw_len)); ++ ++ AuLCntZero(au_lcnt_read(&sbinfo->si_ninodes, /*do_rev*/0)); ++ au_lcnt_fin(&sbinfo->si_ninodes, /*do_sync*/0); ++ AuLCntZero(au_lcnt_read(&sbinfo->si_nfiles, /*do_rev*/0)); ++ au_lcnt_fin(&sbinfo->si_nfiles, /*do_sync*/0); ++ ++ dbgaufs_si_fin(sbinfo); ++ au_rw_write_lock(&sbinfo->si_rwsem); ++ au_br_free(sbinfo); ++ au_rw_write_unlock(&sbinfo->si_rwsem); ++ ++ au_kfree_try_rcu(sbinfo->si_branch); ++ mutex_destroy(&sbinfo->si_xib_mtx); ++ AuRwDestroy(&sbinfo->si_rwsem); ++ ++ au_lcnt_wait_for_fin(&sbinfo->si_ninodes); ++ /* si_nfiles is waited too */ ++ au_kfree_rcu(sbinfo); ++} ++ ++struct au_sbinfo *au_si_alloc(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ int err, i; ++ ++ err = -ENOMEM; ++ sbinfo = kzalloc(sizeof(*sbinfo), GFP_NOFS); ++ if (unlikely(!sbinfo)) ++ goto out; ++ ++ /* will be reallocated separately */ ++ sbinfo->si_branch = kzalloc(sizeof(*sbinfo->si_branch), GFP_NOFS); ++ if (unlikely(!sbinfo->si_branch)) ++ goto out_sbinfo; ++ ++ err = sysaufs_si_init(sbinfo); ++ if (!err) { ++ dbgaufs_si_null(sbinfo); ++ err = dbgaufs_si_init(sbinfo); ++ if (unlikely(err)) ++ kobject_put(&sbinfo->si_kobj); ++ } ++ if (unlikely(err)) ++ goto out_br; ++ ++ au_nwt_init(&sbinfo->si_nowait); ++ au_rw_init_wlock(&sbinfo->si_rwsem); ++ ++ au_lcnt_init(&sbinfo->si_ninodes, /*release*/NULL); ++ au_lcnt_init(&sbinfo->si_nfiles, /*release*/NULL); ++ ++ sbinfo->si_bbot = -1; ++ sbinfo->si_last_br_id = AUFS_BRANCH_MAX / 2; ++ ++ sbinfo->si_wbr_copyup = AuWbrCopyup_Def; ++ sbinfo->si_wbr_create = AuWbrCreate_Def; ++ sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + sbinfo->si_wbr_copyup; ++ sbinfo->si_wbr_create_ops = au_wbr_create_ops + sbinfo->si_wbr_create; ++ ++ au_fhsm_init(sbinfo); ++ ++ sbinfo->si_mntflags = au_opts_plink(AuOpt_Def); ++ ++ sbinfo->si_xino_jiffy = jiffies; ++ sbinfo->si_xino_expire ++ = msecs_to_jiffies(AUFS_XINO_DEF_SEC * MSEC_PER_SEC); ++ mutex_init(&sbinfo->si_xib_mtx); ++ /* leave si_xib_last_pindex and si_xib_next_bit */ ++ ++ INIT_HLIST_BL_HEAD(&sbinfo->si_aopen); ++ ++ sbinfo->si_rdcache = msecs_to_jiffies(AUFS_RDCACHE_DEF * MSEC_PER_SEC); ++ sbinfo->si_rdblk = AUFS_RDBLK_DEF; ++ sbinfo->si_rdhash = AUFS_RDHASH_DEF; ++ sbinfo->si_dirwh = AUFS_DIRWH_DEF; ++ ++ for (i = 0; i < AuPlink_NHASH; i++) ++ INIT_HLIST_BL_HEAD(sbinfo->si_plink + i); ++ init_waitqueue_head(&sbinfo->si_plink_wq); ++ spin_lock_init(&sbinfo->si_plink_maint_lock); ++ ++ INIT_HLIST_BL_HEAD(&sbinfo->si_files); ++ ++ /* with getattr by default */ ++ sbinfo->si_iop_array = aufs_iop; ++ ++ /* leave other members for sysaufs and si_mnt. */ ++ sbinfo->si_sb = sb; ++ if (sb) { ++ sb->s_fs_info = sbinfo; ++ si_pid_set(sb); ++ } ++ return sbinfo; /* success */ ++ ++out_br: ++ au_kfree_try_rcu(sbinfo->si_branch); ++out_sbinfo: ++ au_kfree_rcu(sbinfo); ++out: ++ return ERR_PTR(err); ++} ++ ++int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr, int may_shrink) ++{ ++ int err, sz; ++ struct au_branch **brp; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ err = -ENOMEM; ++ sz = sizeof(*brp) * (sbinfo->si_bbot + 1); ++ if (unlikely(!sz)) ++ sz = sizeof(*brp); ++ brp = au_kzrealloc(sbinfo->si_branch, sz, sizeof(*brp) * nbr, GFP_NOFS, ++ may_shrink); ++ if (brp) { ++ sbinfo->si_branch = brp; ++ err = 0; ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++unsigned int au_sigen_inc(struct super_block *sb) ++{ ++ unsigned int gen; ++ struct inode *inode; ++ ++ SiMustWriteLock(sb); ++ ++ gen = ++au_sbi(sb)->si_generation; ++ au_update_digen(sb->s_root); ++ inode = d_inode(sb->s_root); ++ au_update_iigen(inode, /*half*/0); ++ inode_inc_iversion(inode); ++ return gen; ++} ++ ++aufs_bindex_t au_new_br_id(struct super_block *sb) ++{ ++ aufs_bindex_t br_id; ++ int i; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ for (i = 0; i <= AUFS_BRANCH_MAX; i++) { ++ br_id = ++sbinfo->si_last_br_id; ++ AuDebugOn(br_id < 0); ++ if (br_id && au_br_index(sb, br_id) < 0) ++ return br_id; ++ } ++ ++ return -1; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* it is ok that new 'nwt' tasks are appended while we are sleeping */ ++int si_read_lock(struct super_block *sb, int flags) ++{ ++ int err; ++ ++ err = 0; ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ ++ si_noflush_read_lock(sb); ++ err = au_plink_maint(sb, flags); ++ if (unlikely(err)) ++ si_read_unlock(sb); ++ ++ return err; ++} ++ ++int si_write_lock(struct super_block *sb, int flags) ++{ ++ int err; ++ ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ ++ si_noflush_write_lock(sb); ++ err = au_plink_maint(sb, flags); ++ if (unlikely(err)) ++ si_write_unlock(sb); ++ ++ return err; ++} ++ ++/* dentry and super_block lock. call at entry point */ ++int aufs_read_lock(struct dentry *dentry, int flags) ++{ ++ int err; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ err = si_read_lock(sb, flags); ++ if (unlikely(err)) ++ goto out; ++ ++ if (au_ftest_lock(flags, DW)) ++ di_write_lock_child(dentry); ++ else ++ di_read_lock_child(dentry, flags); ++ ++ if (au_ftest_lock(flags, GEN)) { ++ err = au_digen_test(dentry, au_sigen(sb)); ++ if (!au_opt_test(au_mntflags(sb), UDBA_NONE)) ++ AuDebugOn(!err && au_dbrange_test(dentry)); ++ else if (!err) ++ err = au_dbrange_test(dentry); ++ if (unlikely(err)) ++ aufs_read_unlock(dentry, flags); ++ } ++ ++out: ++ return err; ++} ++ ++void aufs_read_unlock(struct dentry *dentry, int flags) ++{ ++ if (au_ftest_lock(flags, DW)) ++ di_write_unlock(dentry); ++ else ++ di_read_unlock(dentry, flags); ++ si_read_unlock(dentry->d_sb); ++} ++ ++void aufs_write_lock(struct dentry *dentry) ++{ ++ si_write_lock(dentry->d_sb, AuLock_FLUSH | AuLock_NOPLMW); ++ di_write_lock_child(dentry); ++} ++ ++void aufs_write_unlock(struct dentry *dentry) ++{ ++ di_write_unlock(dentry); ++ si_write_unlock(dentry->d_sb); ++} ++ ++int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags) ++{ ++ int err; ++ unsigned int sigen; ++ struct super_block *sb; ++ ++ sb = d1->d_sb; ++ err = si_read_lock(sb, flags); ++ if (unlikely(err)) ++ goto out; ++ ++ di_write_lock2_child(d1, d2, au_ftest_lock(flags, DIRS)); ++ ++ if (au_ftest_lock(flags, GEN)) { ++ sigen = au_sigen(sb); ++ err = au_digen_test(d1, sigen); ++ AuDebugOn(!err && au_dbrange_test(d1)); ++ if (!err) { ++ err = au_digen_test(d2, sigen); ++ AuDebugOn(!err && au_dbrange_test(d2)); ++ } ++ if (unlikely(err)) ++ aufs_read_and_write_unlock2(d1, d2); ++ } ++ ++out: ++ return err; ++} ++ ++void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2) ++{ ++ di_write_unlock2(d1, d2); ++ si_read_unlock(d1->d_sb); ++} +diff -Naur null/fs/aufs/super.c linux-5.15.36/fs/aufs/super.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/super.c 2022-05-10 16:51:39.876744219 +0300 +@@ -0,0 +1,871 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * mount and super_block operations ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++/* ++ * super_operations ++ */ ++static struct inode *aufs_alloc_inode(struct super_block *sb __maybe_unused) ++{ ++ struct au_icntnr *c; ++ ++ c = au_cache_alloc_icntnr(); ++ if (c) { ++ au_icntnr_init(c); ++ inode_set_iversion(&c->vfs_inode, 1); /* sigen(sb); */ ++ c->iinfo.ii_hinode = NULL; ++ return &c->vfs_inode; ++ } ++ return NULL; ++} ++ ++static void aufs_destroy_inode(struct inode *inode) ++{ ++ if (!au_is_bad_inode(inode)) ++ au_iinfo_fin(inode); ++} ++ ++static void aufs_free_inode(struct inode *inode) ++{ ++ au_cache_free_icntnr(container_of(inode, struct au_icntnr, vfs_inode)); ++} ++ ++struct inode *au_iget_locked(struct super_block *sb, ino_t ino) ++{ ++ struct inode *inode; ++ int err; ++ ++ inode = iget_locked(sb, ino); ++ if (unlikely(!inode)) { ++ inode = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ if (!(inode->i_state & I_NEW)) ++ goto out; ++ ++ err = au_xigen_new(inode); ++ if (!err) ++ err = au_iinfo_init(inode); ++ if (!err) ++ inode_inc_iversion(inode); ++ else { ++ iget_failed(inode); ++ inode = ERR_PTR(err); ++ } ++ ++out: ++ /* never return NULL */ ++ AuDebugOn(!inode); ++ AuTraceErrPtr(inode); ++ return inode; ++} ++ ++/* lock free root dinfo */ ++static int au_show_brs(struct seq_file *seq, struct super_block *sb) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct path path; ++ struct au_hdentry *hdp; ++ struct au_branch *br; ++ au_br_perm_str_t perm; ++ ++ err = 0; ++ bbot = au_sbbot(sb); ++ bindex = 0; ++ hdp = au_hdentry(au_di(sb->s_root), bindex); ++ for (; !err && bindex <= bbot; bindex++, hdp++) { ++ br = au_sbr(sb, bindex); ++ path.mnt = au_br_mnt(br); ++ path.dentry = hdp->hd_dentry; ++ err = au_seq_path(seq, &path); ++ if (!err) { ++ au_optstr_br_perm(&perm, br->br_perm); ++ seq_printf(seq, "=%s", perm.a); ++ if (bindex != bbot) ++ seq_putc(seq, ':'); ++ } ++ } ++ if (unlikely(err || seq_has_overflowed(seq))) ++ err = -E2BIG; ++ ++ return err; ++} ++ ++static void au_gen_fmt(char *fmt, int len __maybe_unused, const char *pat, ++ const char *append) ++{ ++ char *p; ++ ++ p = fmt; ++ while (*pat != ':') ++ *p++ = *pat++; ++ *p++ = *pat++; ++ strcpy(p, append); ++ AuDebugOn(strlen(fmt) >= len); ++} ++ ++static void au_show_wbr_create(struct seq_file *m, int v, ++ struct au_sbinfo *sbinfo) ++{ ++ const char *pat; ++ char fmt[32]; ++ struct au_wbr_mfs *mfs; ++ ++ AuRwMustAnyLock(&sbinfo->si_rwsem); ++ ++ seq_puts(m, ",create="); ++ pat = au_optstr_wbr_create(v); ++ mfs = &sbinfo->si_wbr_mfs; ++ switch (v) { ++ case AuWbrCreate_TDP: ++ case AuWbrCreate_RR: ++ case AuWbrCreate_MFS: ++ case AuWbrCreate_PMFS: ++ seq_puts(m, pat); ++ break; ++ case AuWbrCreate_MFSRR: ++ case AuWbrCreate_TDMFS: ++ case AuWbrCreate_PMFSRR: ++ au_gen_fmt(fmt, sizeof(fmt), pat, "%llu"); ++ seq_printf(m, fmt, mfs->mfsrr_watermark); ++ break; ++ case AuWbrCreate_MFSV: ++ case AuWbrCreate_PMFSV: ++ au_gen_fmt(fmt, sizeof(fmt), pat, "%lu"); ++ seq_printf(m, fmt, ++ jiffies_to_msecs(mfs->mfs_expire) ++ / MSEC_PER_SEC); ++ break; ++ case AuWbrCreate_MFSRRV: ++ case AuWbrCreate_TDMFSV: ++ case AuWbrCreate_PMFSRRV: ++ au_gen_fmt(fmt, sizeof(fmt), pat, "%llu:%lu"); ++ seq_printf(m, fmt, mfs->mfsrr_watermark, ++ jiffies_to_msecs(mfs->mfs_expire) / MSEC_PER_SEC); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++static int au_show_xino(struct seq_file *seq, struct super_block *sb) ++{ ++#ifdef CONFIG_SYSFS ++ return 0; ++#else ++ int err; ++ const int len = sizeof(AUFS_XINO_FNAME) - 1; ++ aufs_bindex_t bindex, brid; ++ struct qstr *name; ++ struct file *f; ++ struct dentry *d, *h_root; ++ struct au_branch *br; ++ ++ AuRwMustAnyLock(&sbinfo->si_rwsem); ++ ++ err = 0; ++ f = au_sbi(sb)->si_xib; ++ if (!f) ++ goto out; ++ ++ /* stop printing the default xino path on the first writable branch */ ++ h_root = NULL; ++ bindex = au_xi_root(sb, f->f_path.dentry); ++ if (bindex >= 0) { ++ br = au_sbr_sb(sb, bindex); ++ h_root = au_br_dentry(br); ++ } ++ ++ d = f->f_path.dentry; ++ name = &d->d_name; ++ /* safe ->d_parent because the file is unlinked */ ++ if (d->d_parent == h_root ++ && name->len == len ++ && !memcmp(name->name, AUFS_XINO_FNAME, len)) ++ goto out; ++ ++ seq_puts(seq, ",xino="); ++ err = au_xino_path(seq, f); ++ ++out: ++ return err; ++#endif ++} ++ ++/* seq_file will re-call me in case of too long string */ ++static int aufs_show_options(struct seq_file *m, struct dentry *dentry) ++{ ++ int err; ++ unsigned int mnt_flags, v; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ ++#define AuBool(name, str) do { \ ++ v = au_opt_test(mnt_flags, name); \ ++ if (v != au_opt_test(AuOpt_Def, name)) \ ++ seq_printf(m, ",%s" #str, v ? "" : "no"); \ ++} while (0) ++ ++#define AuStr(name, str) do { \ ++ v = mnt_flags & AuOptMask_##name; \ ++ if (v != (AuOpt_Def & AuOptMask_##name)) \ ++ seq_printf(m, "," #str "=%s", au_optstr_##str(v)); \ ++} while (0) ++ ++#define AuUInt(name, str, val) do { \ ++ if (val != AUFS_##name##_DEF) \ ++ seq_printf(m, "," #str "=%u", val); \ ++} while (0) ++ ++ sb = dentry->d_sb; ++ if (sb->s_flags & SB_POSIXACL) ++ seq_puts(m, ",acl"); ++#if 0 /* reserved for future use */ ++ if (sb->s_flags & SB_I_VERSION) ++ seq_puts(m, ",i_version"); ++#endif ++ ++ /* lock free root dinfo */ ++ si_noflush_read_lock(sb); ++ sbinfo = au_sbi(sb); ++ seq_printf(m, ",si=%lx", sysaufs_si_id(sbinfo)); ++ ++ mnt_flags = au_mntflags(sb); ++ if (au_opt_test(mnt_flags, XINO)) { ++ err = au_show_xino(m, sb); ++ if (unlikely(err)) ++ goto out; ++ } else ++ seq_puts(m, ",noxino"); ++ ++ AuBool(TRUNC_XINO, trunc_xino); ++ AuStr(UDBA, udba); ++ AuBool(SHWH, shwh); ++ AuBool(PLINK, plink); ++ AuBool(DIO, dio); ++ AuBool(DIRPERM1, dirperm1); ++ ++ v = sbinfo->si_wbr_create; ++ if (v != AuWbrCreate_Def) ++ au_show_wbr_create(m, v, sbinfo); ++ ++ v = sbinfo->si_wbr_copyup; ++ if (v != AuWbrCopyup_Def) ++ seq_printf(m, ",cpup=%s", au_optstr_wbr_copyup(v)); ++ ++ v = au_opt_test(mnt_flags, ALWAYS_DIROPQ); ++ if (v != au_opt_test(AuOpt_Def, ALWAYS_DIROPQ)) ++ seq_printf(m, ",diropq=%c", v ? 'a' : 'w'); ++ ++ AuUInt(DIRWH, dirwh, sbinfo->si_dirwh); ++ ++ v = jiffies_to_msecs(sbinfo->si_rdcache) / MSEC_PER_SEC; ++ AuUInt(RDCACHE, rdcache, v); ++ ++ AuUInt(RDBLK, rdblk, sbinfo->si_rdblk); ++ AuUInt(RDHASH, rdhash, sbinfo->si_rdhash); ++ ++ au_fhsm_show(m, sbinfo); ++ ++ AuBool(DIRREN, dirren); ++ AuBool(SUM, sum); ++ /* AuBool(SUM_W, wsum); */ ++ AuBool(WARN_PERM, warn_perm); ++ AuBool(VERBOSE, verbose); ++ ++out: ++ /* be sure to print "br:" last */ ++ if (!sysaufs_brs) { ++ seq_puts(m, ",br:"); ++ au_show_brs(m, sb); ++ } ++ si_read_unlock(sb); ++ return 0; ++ ++#undef AuBool ++#undef AuStr ++#undef AuUInt ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* sum mode which returns the summation for statfs(2) */ ++ ++static u64 au_add_till_max(u64 a, u64 b) ++{ ++ u64 old; ++ ++ old = a; ++ a += b; ++ if (old <= a) ++ return a; ++ return ULLONG_MAX; ++} ++ ++static u64 au_mul_till_max(u64 a, long mul) ++{ ++ u64 old; ++ ++ old = a; ++ a *= mul; ++ if (old <= a) ++ return a; ++ return ULLONG_MAX; ++} ++ ++static int au_statfs_sum(struct super_block *sb, struct kstatfs *buf) ++{ ++ int err; ++ long bsize, factor; ++ u64 blocks, bfree, bavail, files, ffree; ++ aufs_bindex_t bbot, bindex, i; ++ unsigned char shared; ++ struct path h_path; ++ struct super_block *h_sb; ++ ++ err = 0; ++ bsize = LONG_MAX; ++ files = 0; ++ ffree = 0; ++ blocks = 0; ++ bfree = 0; ++ bavail = 0; ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ h_path.mnt = au_sbr_mnt(sb, bindex); ++ h_sb = h_path.mnt->mnt_sb; ++ shared = 0; ++ for (i = 0; !shared && i < bindex; i++) ++ shared = (au_sbr_sb(sb, i) == h_sb); ++ if (shared) ++ continue; ++ ++ /* sb->s_root for NFS is unreliable */ ++ h_path.dentry = h_path.mnt->mnt_root; ++ err = vfs_statfs(&h_path, buf); ++ if (unlikely(err)) ++ goto out; ++ ++ if (bsize > buf->f_bsize) { ++ /* ++ * we will reduce bsize, so we have to expand blocks ++ * etc. to match them again ++ */ ++ factor = (bsize / buf->f_bsize); ++ blocks = au_mul_till_max(blocks, factor); ++ bfree = au_mul_till_max(bfree, factor); ++ bavail = au_mul_till_max(bavail, factor); ++ bsize = buf->f_bsize; ++ } ++ ++ factor = (buf->f_bsize / bsize); ++ blocks = au_add_till_max(blocks, ++ au_mul_till_max(buf->f_blocks, factor)); ++ bfree = au_add_till_max(bfree, ++ au_mul_till_max(buf->f_bfree, factor)); ++ bavail = au_add_till_max(bavail, ++ au_mul_till_max(buf->f_bavail, factor)); ++ files = au_add_till_max(files, buf->f_files); ++ ffree = au_add_till_max(ffree, buf->f_ffree); ++ } ++ ++ buf->f_bsize = bsize; ++ buf->f_blocks = blocks; ++ buf->f_bfree = bfree; ++ buf->f_bavail = bavail; ++ buf->f_files = files; ++ buf->f_ffree = ffree; ++ buf->f_frsize = 0; ++ ++out: ++ return err; ++} ++ ++static int aufs_statfs(struct dentry *dentry, struct kstatfs *buf) ++{ ++ int err; ++ struct path h_path; ++ struct super_block *sb; ++ ++ /* lock free root dinfo */ ++ sb = dentry->d_sb; ++ si_noflush_read_lock(sb); ++ if (!au_opt_test(au_mntflags(sb), SUM)) { ++ /* sb->s_root for NFS is unreliable */ ++ h_path.mnt = au_sbr_mnt(sb, 0); ++ h_path.dentry = h_path.mnt->mnt_root; ++ err = vfs_statfs(&h_path, buf); ++ } else ++ err = au_statfs_sum(sb, buf); ++ si_read_unlock(sb); ++ ++ if (!err) { ++ buf->f_type = AUFS_SUPER_MAGIC; ++ buf->f_namelen = AUFS_MAX_NAMELEN; ++ memset(&buf->f_fsid, 0, sizeof(buf->f_fsid)); ++ } ++ /* buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1; */ ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_sync_fs(struct super_block *sb, int wait) ++{ ++ int err, e; ++ aufs_bindex_t bbot, bindex; ++ struct au_branch *br; ++ struct super_block *h_sb; ++ ++ err = 0; ++ si_noflush_read_lock(sb); ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!au_br_writable(br->br_perm)) ++ continue; ++ ++ h_sb = au_sbr_sb(sb, bindex); ++ e = vfsub_sync_filesystem(h_sb); ++ if (unlikely(e && !err)) ++ err = e; ++ /* go on even if an error happens */ ++ } ++ si_read_unlock(sb); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* final actions when unmounting a file system */ ++static void aufs_put_super(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ sbinfo = au_sbi(sb); ++ if (sbinfo) ++ kobject_put(&sbinfo->si_kobj); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, ++ struct super_block *sb, void *arg) ++{ ++ void *array; ++ unsigned long long n, sz; ++ ++ array = NULL; ++ n = 0; ++ if (!*hint) ++ goto out; ++ ++ if (*hint > ULLONG_MAX / sizeof(array)) { ++ array = ERR_PTR(-EMFILE); ++ pr_err("hint %llu\n", *hint); ++ goto out; ++ } ++ ++ sz = sizeof(array) * *hint; ++ array = kzalloc(sz, GFP_NOFS); ++ if (unlikely(!array)) ++ array = vzalloc(sz); ++ if (unlikely(!array)) { ++ array = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ ++ n = cb(sb, array, *hint, arg); ++ AuDebugOn(n > *hint); ++ ++out: ++ *hint = n; ++ return array; ++} ++ ++static unsigned long long au_iarray_cb(struct super_block *sb, void *a, ++ unsigned long long max __maybe_unused, ++ void *arg) ++{ ++ unsigned long long n; ++ struct inode **p, *inode; ++ struct list_head *head; ++ ++ n = 0; ++ p = a; ++ head = arg; ++ spin_lock(&sb->s_inode_list_lock); ++ list_for_each_entry(inode, head, i_sb_list) { ++ if (!au_is_bad_inode(inode) ++ && au_ii(inode)->ii_btop >= 0) { ++ spin_lock(&inode->i_lock); ++ if (atomic_read(&inode->i_count)) { ++ au_igrab(inode); ++ *p++ = inode; ++ n++; ++ AuDebugOn(n > max); ++ } ++ spin_unlock(&inode->i_lock); ++ } ++ } ++ spin_unlock(&sb->s_inode_list_lock); ++ ++ return n; ++} ++ ++struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max) ++{ ++ struct au_sbinfo *sbi; ++ ++ sbi = au_sbi(sb); ++ *max = au_lcnt_read(&sbi->si_ninodes, /*do_rev*/1); ++ return au_array_alloc(max, au_iarray_cb, sb, &sb->s_inodes); ++} ++ ++void au_iarray_free(struct inode **a, unsigned long long max) ++{ ++ unsigned long long ull; ++ ++ for (ull = 0; ull < max; ull++) ++ iput(a[ull]); ++ kvfree(a); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * refresh dentry and inode at remount time. ++ */ ++/* todo: consolidate with simple_reval_dpath() and au_reval_for_attr() */ ++static int au_do_refresh(struct dentry *dentry, unsigned int dir_flags, ++ struct dentry *parent) ++{ ++ int err; ++ ++ di_write_lock_child(dentry); ++ di_read_lock_parent(parent, AuLock_IR); ++ err = au_refresh_dentry(dentry, parent); ++ if (!err && dir_flags) ++ au_hn_reset(d_inode(dentry), dir_flags); ++ di_read_unlock(parent, AuLock_IR); ++ di_write_unlock(dentry); ++ ++ return err; ++} ++ ++static int au_do_refresh_d(struct dentry *dentry, unsigned int sigen, ++ struct au_sbinfo *sbinfo, ++ const unsigned int dir_flags, unsigned int do_idop) ++{ ++ int err; ++ struct dentry *parent; ++ ++ err = 0; ++ parent = dget_parent(dentry); ++ if (!au_digen_test(parent, sigen) && au_digen_test(dentry, sigen)) { ++ if (d_really_is_positive(dentry)) { ++ if (!d_is_dir(dentry)) ++ err = au_do_refresh(dentry, /*dir_flags*/0, ++ parent); ++ else { ++ err = au_do_refresh(dentry, dir_flags, parent); ++ if (unlikely(err)) ++ au_fset_si(sbinfo, FAILED_REFRESH_DIR); ++ } ++ } else ++ err = au_do_refresh(dentry, /*dir_flags*/0, parent); ++ AuDbgDentry(dentry); ++ } ++ dput(parent); ++ ++ if (!err) { ++ if (do_idop) ++ au_refresh_dop(dentry, /*force_reval*/0); ++ } else ++ au_refresh_dop(dentry, /*force_reval*/1); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_refresh_d(struct super_block *sb, unsigned int do_idop) ++{ ++ int err, i, j, ndentry, e; ++ unsigned int sigen; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries, *d; ++ struct au_sbinfo *sbinfo; ++ struct dentry *root = sb->s_root; ++ const unsigned int dir_flags = au_hi_flags(d_inode(root), /*isdir*/1); ++ ++ if (do_idop) ++ au_refresh_dop(root, /*force_reval*/0); ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, root, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ sigen = au_sigen(sb); ++ sbinfo = au_sbi(sb); ++ for (i = 0; i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ ndentry = dpage->ndentry; ++ for (j = 0; j < ndentry; j++) { ++ d = dentries[j]; ++ e = au_do_refresh_d(d, sigen, sbinfo, dir_flags, ++ do_idop); ++ if (unlikely(e && !err)) ++ err = e; ++ /* go on even err */ ++ } ++ } ++ ++out_dpages: ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++static int au_refresh_i(struct super_block *sb, unsigned int do_idop) ++{ ++ int err, e; ++ unsigned int sigen; ++ unsigned long long max, ull; ++ struct inode *inode, **array; ++ ++ array = au_iarray_alloc(sb, &max); ++ err = PTR_ERR(array); ++ if (IS_ERR(array)) ++ goto out; ++ ++ err = 0; ++ sigen = au_sigen(sb); ++ for (ull = 0; ull < max; ull++) { ++ inode = array[ull]; ++ if (unlikely(!inode)) ++ break; ++ ++ e = 0; ++ ii_write_lock_child(inode); ++ if (au_iigen(inode, NULL) != sigen) { ++ e = au_refresh_hinode_self(inode); ++ if (unlikely(e)) { ++ au_refresh_iop(inode, /*force_getattr*/1); ++ pr_err("error %d, i%lu\n", e, inode->i_ino); ++ if (!err) ++ err = e; ++ /* go on even if err */ ++ } ++ } ++ if (!e && do_idop) ++ au_refresh_iop(inode, /*force_getattr*/0); ++ ii_write_unlock(inode); ++ } ++ ++ au_iarray_free(array, max); ++ ++out: ++ return err; ++} ++ ++void au_remount_refresh(struct super_block *sb, unsigned int do_idop) ++{ ++ int err, e; ++ unsigned int udba; ++ aufs_bindex_t bindex, bbot; ++ struct dentry *root; ++ struct inode *inode; ++ struct au_branch *br; ++ struct au_sbinfo *sbi; ++ ++ au_sigen_inc(sb); ++ sbi = au_sbi(sb); ++ au_fclr_si(sbi, FAILED_REFRESH_DIR); ++ ++ root = sb->s_root; ++ DiMustNoWaiters(root); ++ inode = d_inode(root); ++ IiMustNoWaiters(inode); ++ ++ udba = au_opt_udba(sb); ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ err = au_hnotify_reset_br(udba, br, br->br_perm); ++ if (unlikely(err)) ++ AuIOErr("hnotify failed on br %d, %d, ignored\n", ++ bindex, err); ++ /* go on even if err */ ++ } ++ au_hn_reset(inode, au_hi_flags(inode, /*isdir*/1)); ++ ++ if (do_idop) { ++ if (au_ftest_si(sbi, NO_DREVAL)) { ++ AuDebugOn(sb->s_d_op == &aufs_dop_noreval); ++ sb->s_d_op = &aufs_dop_noreval; ++ AuDebugOn(sbi->si_iop_array == aufs_iop_nogetattr); ++ sbi->si_iop_array = aufs_iop_nogetattr; ++ } else { ++ AuDebugOn(sb->s_d_op == &aufs_dop); ++ sb->s_d_op = &aufs_dop; ++ AuDebugOn(sbi->si_iop_array == aufs_iop); ++ sbi->si_iop_array = aufs_iop; ++ } ++ pr_info("reset to %ps and %ps\n", ++ sb->s_d_op, sbi->si_iop_array); ++ } ++ ++ di_write_unlock(root); ++ err = au_refresh_d(sb, do_idop); ++ e = au_refresh_i(sb, do_idop); ++ if (unlikely(e && !err)) ++ err = e; ++ /* aufs_write_lock() calls ..._child() */ ++ di_write_lock_child(root); ++ ++ au_cpup_attr_all(inode, /*force*/1); ++ ++ if (unlikely(err)) ++ AuIOErr("refresh failed, ignored, %d\n", err); ++} ++ ++const struct super_operations aufs_sop = { ++ .alloc_inode = aufs_alloc_inode, ++ .destroy_inode = aufs_destroy_inode, ++ .free_inode = aufs_free_inode, ++ /* always deleting, no clearing */ ++ .drop_inode = generic_delete_inode, ++ .show_options = aufs_show_options, ++ .statfs = aufs_statfs, ++ .put_super = aufs_put_super, ++ .sync_fs = aufs_sync_fs ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_alloc_root(struct super_block *sb) ++{ ++ int err; ++ struct inode *inode; ++ struct dentry *root; ++ ++ err = -ENOMEM; ++ inode = au_iget_locked(sb, AUFS_ROOT_INO); ++ err = PTR_ERR(inode); ++ if (IS_ERR(inode)) ++ goto out; ++ ++ inode->i_op = aufs_iop + AuIop_DIR; /* with getattr by default */ ++ inode->i_fop = &aufs_dir_fop; ++ inode->i_mode = S_IFDIR; ++ set_nlink(inode, 2); ++ unlock_new_inode(inode); ++ ++ root = d_make_root(inode); ++ if (unlikely(!root)) ++ goto out; ++ err = PTR_ERR(root); ++ if (IS_ERR(root)) ++ goto out; ++ ++ err = au_di_init(root); ++ if (!err) { ++ sb->s_root = root; ++ return 0; /* success */ ++ } ++ dput(root); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void aufs_kill_sb(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ struct dentry *root; ++ ++ sbinfo = au_sbi(sb); ++ if (!sbinfo) ++ goto out; ++ ++ au_sbilist_del(sb); ++ ++ root = sb->s_root; ++ if (root) ++ aufs_write_lock(root); ++ else ++ __si_write_lock(sb); ++ ++ au_fhsm_fin(sb); ++ if (sbinfo->si_wbr_create_ops->fin) ++ sbinfo->si_wbr_create_ops->fin(sb); ++ if (au_opt_test(sbinfo->si_mntflags, UDBA_HNOTIFY)) { ++ au_opt_set_udba(sbinfo->si_mntflags, UDBA_NONE); ++ au_remount_refresh(sb, /*do_idop*/0); ++ } ++ if (au_opt_test(sbinfo->si_mntflags, PLINK)) ++ au_plink_put(sb, /*verbose*/1); ++ au_xino_clr(sb); ++ if (root) ++ au_dr_opt_flush(sb); ++ ++ if (root) ++ aufs_write_unlock(root); ++ else ++ __si_write_unlock(sb); ++ ++ sbinfo->si_sb = NULL; ++ au_nwt_flush(&sbinfo->si_nowait); ++ ++out: ++ kill_anon_super(sb); ++} ++ ++struct file_system_type aufs_fs_type = { ++ .name = AUFS_FSTYPE, ++ /* a race between rename and others */ ++ .fs_flags = FS_RENAME_DOES_D_MOVE ++ /* untested */ ++ /*| FS_ALLOW_IDMAP*/ ++ , ++ .init_fs_context = aufs_fsctx_init, ++ .parameters = aufs_fsctx_paramspec, ++ .kill_sb = aufs_kill_sb, ++ /* no need to __module_get() and module_put(). */ ++ .owner = THIS_MODULE, ++}; +diff -Naur null/fs/aufs/super.h linux-5.15.36/fs/aufs/super.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/super.h 2022-05-10 16:51:39.876744219 +0300 +@@ -0,0 +1,592 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * super_block operations ++ */ ++ ++#ifndef __AUFS_SUPER_H__ ++#define __AUFS_SUPER_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include "hbl.h" ++#include "lcnt.h" ++#include "rwsem.h" ++#include "wkq.h" ++ ++/* policies to select one among multiple writable branches */ ++struct au_wbr_copyup_operations { ++ int (*copyup)(struct dentry *dentry); ++}; ++ ++#define AuWbr_DIR 1 /* target is a dir */ ++#define AuWbr_PARENT (1 << 1) /* always require a parent */ ++ ++#define au_ftest_wbr(flags, name) ((flags) & AuWbr_##name) ++#define au_fset_wbr(flags, name) { (flags) |= AuWbr_##name; } ++#define au_fclr_wbr(flags, name) { (flags) &= ~AuWbr_##name; } ++ ++struct au_wbr_create_operations { ++ int (*create)(struct dentry *dentry, unsigned int flags); ++ int (*init)(struct super_block *sb); ++ int (*fin)(struct super_block *sb); ++}; ++ ++struct au_wbr_mfs { ++ struct mutex mfs_lock; /* protect this structure */ ++ unsigned long mfs_jiffy; ++ unsigned long mfs_expire; ++ aufs_bindex_t mfs_bindex; ++ ++ unsigned long long mfsrr_bytes; ++ unsigned long long mfsrr_watermark; ++}; ++ ++#define AuPlink_NHASH 100 ++static inline int au_plink_hash(ino_t ino) ++{ ++ return ino % AuPlink_NHASH; ++} ++ ++/* File-based Hierarchical Storage Management */ ++struct au_fhsm { ++#ifdef CONFIG_AUFS_FHSM ++ /* allow only one process who can receive the notification */ ++ spinlock_t fhsm_spin; ++ pid_t fhsm_pid; ++ wait_queue_head_t fhsm_wqh; ++ atomic_t fhsm_readable; ++ ++ /* these are protected by si_rwsem */ ++ unsigned long fhsm_expire; ++ aufs_bindex_t fhsm_bottom; ++#endif ++}; ++ ++struct au_branch; ++struct au_sbinfo { ++ /* nowait tasks in the system-wide workqueue */ ++ struct au_nowait_tasks si_nowait; ++ ++ /* ++ * tried sb->s_umount, but failed due to the dependency between i_mutex. ++ * rwsem for au_sbinfo is necessary. ++ */ ++ struct au_rwsem si_rwsem; ++ ++ /* ++ * dirty approach to protect sb->sb_inodes and ->s_files (gone) from ++ * remount. ++ */ ++ au_lcnt_t si_ninodes, si_nfiles; ++ ++ /* branch management */ ++ unsigned int si_generation; ++ ++ /* see AuSi_ flags */ ++ unsigned char au_si_status; ++ ++ aufs_bindex_t si_bbot; ++ ++ /* dirty trick to keep br_id plus */ ++ unsigned int si_last_br_id : ++ sizeof(aufs_bindex_t) * BITS_PER_BYTE - 1; ++ struct au_branch **si_branch; ++ ++ /* policy to select a writable branch */ ++ unsigned char si_wbr_copyup; ++ unsigned char si_wbr_create; ++ struct au_wbr_copyup_operations *si_wbr_copyup_ops; ++ struct au_wbr_create_operations *si_wbr_create_ops; ++ ++ /* round robin */ ++ atomic_t si_wbr_rr_next; ++ ++ /* most free space */ ++ struct au_wbr_mfs si_wbr_mfs; ++ ++ /* File-based Hierarchical Storage Management */ ++ struct au_fhsm si_fhsm; ++ ++ /* mount flags */ ++ /* include/asm-ia64/siginfo.h defines a macro named si_flags */ ++ unsigned int si_mntflags; ++ ++ /* external inode number (bitmap and translation table) */ ++ loff_t si_ximaxent; /* max entries in a xino */ ++ ++ struct file *si_xib; ++ struct mutex si_xib_mtx; /* protect xib members */ ++ unsigned long *si_xib_buf; ++ unsigned long si_xib_last_pindex; ++ int si_xib_next_bit; ++ ++ unsigned long si_xino_jiffy; ++ unsigned long si_xino_expire; ++ /* reserved for future use */ ++ /* unsigned long long si_xib_limit; */ /* Max xib file size */ ++ ++#ifdef CONFIG_AUFS_EXPORT ++ /* i_generation */ ++ /* todo: make xigen file an array to support many inode numbers */ ++ struct file *si_xigen; ++ atomic_t si_xigen_next; ++#endif ++ ++ /* dirty trick to support atomic_open */ ++ struct hlist_bl_head si_aopen; ++ ++ /* vdir parameters */ ++ unsigned long si_rdcache; /* max cache time in jiffies */ ++ unsigned int si_rdblk; /* deblk size */ ++ unsigned int si_rdhash; /* hash size */ ++ ++ /* ++ * If the number of whiteouts are larger than si_dirwh, leave all of ++ * them after au_whtmp_ren to reduce the cost of rmdir(2). ++ * future fsck.aufs or kernel thread will remove them later. ++ * Otherwise, remove all whiteouts and the dir in rmdir(2). ++ */ ++ unsigned int si_dirwh; ++ ++ /* pseudo_link list */ ++ struct hlist_bl_head si_plink[AuPlink_NHASH]; ++ wait_queue_head_t si_plink_wq; ++ spinlock_t si_plink_maint_lock; ++ pid_t si_plink_maint_pid; ++ ++ /* file list */ ++ struct hlist_bl_head si_files; ++ ++ /* with/without getattr, brother of sb->s_d_op */ ++ const struct inode_operations *si_iop_array; ++ ++ /* ++ * sysfs and lifetime management. ++ * this is not a small structure and it may be a waste of memory in case ++ * of sysfs is disabled, particularly when many aufs-es are mounted. ++ * but using sysfs is majority. ++ */ ++ struct kobject si_kobj; ++#ifdef CONFIG_DEBUG_FS ++ struct dentry *si_dbgaufs; ++ struct dentry *si_dbgaufs_plink; ++ struct dentry *si_dbgaufs_xib; ++#ifdef CONFIG_AUFS_EXPORT ++ struct dentry *si_dbgaufs_xigen; ++#endif ++#endif ++ ++#ifdef CONFIG_AUFS_SBILIST ++ struct hlist_bl_node si_list; ++#endif ++ ++ /* dirty, necessary for unmounting, sysfs and sysrq */ ++ struct super_block *si_sb; ++}; ++ ++/* sbinfo status flags */ ++/* ++ * set true when refresh_dirs() failed at remount time. ++ * then try refreshing dirs at access time again. ++ * if it is false, refreshing dirs at access time is unnecessary ++ */ ++#define AuSi_FAILED_REFRESH_DIR 1 ++#define AuSi_FHSM (1 << 1) /* fhsm is active now */ ++#define AuSi_NO_DREVAL (1 << 2) /* disable all d_revalidate */ ++ ++#ifndef CONFIG_AUFS_FHSM ++#undef AuSi_FHSM ++#define AuSi_FHSM 0 ++#endif ++ ++static inline unsigned char au_do_ftest_si(struct au_sbinfo *sbi, ++ unsigned int flag) ++{ ++ AuRwMustAnyLock(&sbi->si_rwsem); ++ return sbi->au_si_status & flag; ++} ++#define au_ftest_si(sbinfo, name) au_do_ftest_si(sbinfo, AuSi_##name) ++#define au_fset_si(sbinfo, name) do { \ ++ AuRwMustWriteLock(&(sbinfo)->si_rwsem); \ ++ (sbinfo)->au_si_status |= AuSi_##name; \ ++} while (0) ++#define au_fclr_si(sbinfo, name) do { \ ++ AuRwMustWriteLock(&(sbinfo)->si_rwsem); \ ++ (sbinfo)->au_si_status &= ~AuSi_##name; \ ++} while (0) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policy to select one among writable branches */ ++#define AuWbrCopyup(sbinfo, ...) \ ++ ((sbinfo)->si_wbr_copyup_ops->copyup(__VA_ARGS__)) ++#define AuWbrCreate(sbinfo, ...) \ ++ ((sbinfo)->si_wbr_create_ops->create(__VA_ARGS__)) ++ ++/* flags for si_read_lock()/aufs_read_lock()/di_read_lock() */ ++#define AuLock_DW 1 /* write-lock dentry */ ++#define AuLock_IR (1 << 1) /* read-lock inode */ ++#define AuLock_IW (1 << 2) /* write-lock inode */ ++#define AuLock_FLUSH (1 << 3) /* wait for 'nowait' tasks */ ++#define AuLock_DIRS (1 << 4) /* target is a pair of dirs */ ++ /* except RENAME_EXCHANGE */ ++#define AuLock_NOPLM (1 << 5) /* return err in plm mode */ ++#define AuLock_NOPLMW (1 << 6) /* wait for plm mode ends */ ++#define AuLock_GEN (1 << 7) /* test digen/iigen */ ++#define au_ftest_lock(flags, name) ((flags) & AuLock_##name) ++#define au_fset_lock(flags, name) \ ++ do { (flags) |= AuLock_##name; } while (0) ++#define au_fclr_lock(flags, name) \ ++ do { (flags) &= ~AuLock_##name; } while (0) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* super.c */ ++struct inode *au_iget_locked(struct super_block *sb, ino_t ino); ++ ++typedef unsigned long long (*au_arraycb_t)(struct super_block *sb, void *array, ++ unsigned long long max, void *arg); ++void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, ++ struct super_block *sb, void *arg); ++struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max); ++void au_iarray_free(struct inode **a, unsigned long long max); ++ ++void au_remount_refresh(struct super_block *sb, unsigned int do_idop); ++extern const struct super_operations aufs_sop; ++int au_alloc_root(struct super_block *sb); ++extern struct file_system_type aufs_fs_type; ++ ++/* sbinfo.c */ ++void au_si_free(struct kobject *kobj); ++struct au_sbinfo *au_si_alloc(struct super_block *sb); ++int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr, int may_shrink); ++ ++unsigned int au_sigen_inc(struct super_block *sb); ++aufs_bindex_t au_new_br_id(struct super_block *sb); ++ ++int si_read_lock(struct super_block *sb, int flags); ++int si_write_lock(struct super_block *sb, int flags); ++int aufs_read_lock(struct dentry *dentry, int flags); ++void aufs_read_unlock(struct dentry *dentry, int flags); ++void aufs_write_lock(struct dentry *dentry); ++void aufs_write_unlock(struct dentry *dentry); ++int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags); ++void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2); ++ ++/* wbr_policy.c */ ++extern struct au_wbr_copyup_operations au_wbr_copyup_ops[]; ++extern struct au_wbr_create_operations au_wbr_create_ops[]; ++int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst); ++int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex); ++int au_wbr_do_copyup_bu(struct dentry *dentry, aufs_bindex_t btop); ++ ++/* mvdown.c */ ++int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *arg); ++ ++#ifdef CONFIG_AUFS_FHSM ++/* fhsm.c */ ++ ++static inline pid_t au_fhsm_pid(struct au_fhsm *fhsm) ++{ ++ pid_t pid; ++ ++ spin_lock(&fhsm->fhsm_spin); ++ pid = fhsm->fhsm_pid; ++ spin_unlock(&fhsm->fhsm_spin); ++ ++ return pid; ++} ++ ++void au_fhsm_wrote(struct super_block *sb, aufs_bindex_t bindex, int force); ++void au_fhsm_wrote_all(struct super_block *sb, int force); ++int au_fhsm_fd(struct super_block *sb, int oflags); ++int au_fhsm_br_alloc(struct au_branch *br); ++void au_fhsm_set_bottom(struct super_block *sb, aufs_bindex_t bindex); ++void au_fhsm_fin(struct super_block *sb); ++void au_fhsm_init(struct au_sbinfo *sbinfo); ++void au_fhsm_set(struct au_sbinfo *sbinfo, unsigned int sec); ++void au_fhsm_show(struct seq_file *seq, struct au_sbinfo *sbinfo); ++#else ++AuStubVoid(au_fhsm_wrote, struct super_block *sb, aufs_bindex_t bindex, ++ int force) ++AuStubVoid(au_fhsm_wrote_all, struct super_block *sb, int force) ++AuStub(int, au_fhsm_fd, return -EOPNOTSUPP, struct super_block *sb, int oflags) ++AuStub(pid_t, au_fhsm_pid, return 0, struct au_fhsm *fhsm) ++AuStubInt0(au_fhsm_br_alloc, struct au_branch *br) ++AuStubVoid(au_fhsm_set_bottom, struct super_block *sb, aufs_bindex_t bindex) ++AuStubVoid(au_fhsm_fin, struct super_block *sb) ++AuStubVoid(au_fhsm_init, struct au_sbinfo *sbinfo) ++AuStubVoid(au_fhsm_set, struct au_sbinfo *sbinfo, unsigned int sec) ++AuStubVoid(au_fhsm_show, struct seq_file *seq, struct au_sbinfo *sbinfo) ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_sbinfo *au_sbi(struct super_block *sb) ++{ ++ return sb->s_fs_info; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_EXPORT ++int au_test_nfsd(void); ++void au_export_init(struct super_block *sb); ++void au_xigen_inc(struct inode *inode); ++int au_xigen_new(struct inode *inode); ++int au_xigen_set(struct super_block *sb, struct path *path); ++void au_xigen_clr(struct super_block *sb); ++ ++static inline int au_busy_or_stale(void) ++{ ++ if (!au_test_nfsd()) ++ return -EBUSY; ++ return -ESTALE; ++} ++#else ++AuStubInt0(au_test_nfsd, void) ++AuStubVoid(au_export_init, struct super_block *sb) ++AuStubVoid(au_xigen_inc, struct inode *inode) ++AuStubInt0(au_xigen_new, struct inode *inode) ++AuStubInt0(au_xigen_set, struct super_block *sb, struct path *path) ++AuStubVoid(au_xigen_clr, struct super_block *sb) ++AuStub(int, au_busy_or_stale, return -EBUSY, void) ++#endif /* CONFIG_AUFS_EXPORT */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_SBILIST ++/* module.c */ ++extern struct hlist_bl_head au_sbilist; ++ ++static inline void au_sbilist_init(void) ++{ ++ INIT_HLIST_BL_HEAD(&au_sbilist); ++} ++ ++static inline void au_sbilist_add(struct super_block *sb) ++{ ++ au_hbl_add(&au_sbi(sb)->si_list, &au_sbilist); ++} ++ ++static inline void au_sbilist_del(struct super_block *sb) ++{ ++ au_hbl_del(&au_sbi(sb)->si_list, &au_sbilist); ++} ++ ++#ifdef CONFIG_AUFS_MAGIC_SYSRQ ++static inline void au_sbilist_lock(void) ++{ ++ hlist_bl_lock(&au_sbilist); ++} ++ ++static inline void au_sbilist_unlock(void) ++{ ++ hlist_bl_unlock(&au_sbilist); ++} ++#define AuGFP_SBILIST GFP_ATOMIC ++#else ++AuStubVoid(au_sbilist_lock, void) ++AuStubVoid(au_sbilist_unlock, void) ++#define AuGFP_SBILIST GFP_NOFS ++#endif /* CONFIG_AUFS_MAGIC_SYSRQ */ ++#else ++AuStubVoid(au_sbilist_init, void) ++AuStubVoid(au_sbilist_add, struct super_block *sb) ++AuStubVoid(au_sbilist_del, struct super_block *sb) ++AuStubVoid(au_sbilist_lock, void) ++AuStubVoid(au_sbilist_unlock, void) ++#define AuGFP_SBILIST GFP_NOFS ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline void dbgaufs_si_null(struct au_sbinfo *sbinfo) ++{ ++ /* ++ * This function is a dynamic '__init' function actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++#ifdef CONFIG_DEBUG_FS ++ sbinfo->si_dbgaufs = NULL; ++ sbinfo->si_dbgaufs_plink = NULL; ++ sbinfo->si_dbgaufs_xib = NULL; ++#ifdef CONFIG_AUFS_EXPORT ++ sbinfo->si_dbgaufs_xigen = NULL; ++#endif ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* current->atomic_flags */ ++/* this value should never corrupt the ones defined in linux/sched.h */ ++#define PFA_AUFS 0x10 ++ ++TASK_PFA_TEST(AUFS, test_aufs) /* task_test_aufs */ ++TASK_PFA_SET(AUFS, aufs) /* task_set_aufs */ ++TASK_PFA_CLEAR(AUFS, aufs) /* task_clear_aufs */ ++ ++static inline int si_pid_test(struct super_block *sb) ++{ ++ return !!task_test_aufs(current); ++} ++ ++static inline void si_pid_clr(struct super_block *sb) ++{ ++ AuDebugOn(!task_test_aufs(current)); ++ task_clear_aufs(current); ++} ++ ++static inline void si_pid_set(struct super_block *sb) ++{ ++ AuDebugOn(task_test_aufs(current)); ++ task_set_aufs(current); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock superblock. mainly for entry point functions */ ++#define __si_read_lock(sb) au_rw_read_lock(&au_sbi(sb)->si_rwsem) ++#define __si_write_lock(sb) au_rw_write_lock(&au_sbi(sb)->si_rwsem) ++#define __si_read_trylock(sb) au_rw_read_trylock(&au_sbi(sb)->si_rwsem) ++#define __si_write_trylock(sb) au_rw_write_trylock(&au_sbi(sb)->si_rwsem) ++/* ++#define __si_read_trylock_nested(sb) \ ++ au_rw_read_trylock_nested(&au_sbi(sb)->si_rwsem) ++#define __si_write_trylock_nested(sb) \ ++ au_rw_write_trylock_nested(&au_sbi(sb)->si_rwsem) ++*/ ++ ++#define __si_read_unlock(sb) au_rw_read_unlock(&au_sbi(sb)->si_rwsem) ++#define __si_write_unlock(sb) au_rw_write_unlock(&au_sbi(sb)->si_rwsem) ++#define __si_downgrade_lock(sb) au_rw_dgrade_lock(&au_sbi(sb)->si_rwsem) ++ ++#define SiMustNoWaiters(sb) AuRwMustNoWaiters(&au_sbi(sb)->si_rwsem) ++#define SiMustAnyLock(sb) AuRwMustAnyLock(&au_sbi(sb)->si_rwsem) ++#define SiMustWriteLock(sb) AuRwMustWriteLock(&au_sbi(sb)->si_rwsem) ++ ++static inline void si_noflush_read_lock(struct super_block *sb) ++{ ++ __si_read_lock(sb); ++ si_pid_set(sb); ++} ++ ++static inline int si_noflush_read_trylock(struct super_block *sb) ++{ ++ int locked; ++ ++ locked = __si_read_trylock(sb); ++ if (locked) ++ si_pid_set(sb); ++ return locked; ++} ++ ++static inline void si_noflush_write_lock(struct super_block *sb) ++{ ++ __si_write_lock(sb); ++ si_pid_set(sb); ++} ++ ++static inline int si_noflush_write_trylock(struct super_block *sb) ++{ ++ int locked; ++ ++ locked = __si_write_trylock(sb); ++ if (locked) ++ si_pid_set(sb); ++ return locked; ++} ++ ++#if 0 /* reserved */ ++static inline int si_read_trylock(struct super_block *sb, int flags) ++{ ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ return si_noflush_read_trylock(sb); ++} ++#endif ++ ++static inline void si_read_unlock(struct super_block *sb) ++{ ++ si_pid_clr(sb); ++ __si_read_unlock(sb); ++} ++ ++#if 0 /* reserved */ ++static inline int si_write_trylock(struct super_block *sb, int flags) ++{ ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ return si_noflush_write_trylock(sb); ++} ++#endif ++ ++static inline void si_write_unlock(struct super_block *sb) ++{ ++ si_pid_clr(sb); ++ __si_write_unlock(sb); ++} ++ ++#if 0 /* reserved */ ++static inline void si_downgrade_lock(struct super_block *sb) ++{ ++ __si_downgrade_lock(sb); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline aufs_bindex_t au_sbbot(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_bbot; ++} ++ ++static inline unsigned int au_mntflags(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_mntflags; ++} ++ ++static inline unsigned int au_sigen(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_generation; ++} ++ ++static inline struct au_branch *au_sbr(struct super_block *sb, ++ aufs_bindex_t bindex) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_branch[0 + bindex]; ++} ++ ++static inline loff_t au_xi_maxent(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_ximaxent; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_SUPER_H__ */ +diff -Naur null/fs/aufs/sysaufs.c linux-5.15.36/fs/aufs/sysaufs.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/sysaufs.c 2022-05-10 16:51:39.876744219 +0300 +@@ -0,0 +1,93 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * sysfs interface and lifetime management ++ * they are necessary regardless sysfs is disabled. ++ */ ++ ++#include ++#include "aufs.h" ++ ++unsigned long sysaufs_si_mask; ++struct kset *sysaufs_kset; ++ ++#define AuSiAttr(_name) { \ ++ .attr = { .name = __stringify(_name), .mode = 0444 }, \ ++ .show = sysaufs_si_##_name, \ ++} ++ ++static struct sysaufs_si_attr sysaufs_si_attr_xi_path = AuSiAttr(xi_path); ++struct attribute *sysaufs_si_attrs[] = { ++ &sysaufs_si_attr_xi_path.attr, ++ NULL, ++}; ++ ++static const struct sysfs_ops au_sbi_ops = { ++ .show = sysaufs_si_show ++}; ++ ++static struct kobj_type au_sbi_ktype = { ++ .release = au_si_free, ++ .sysfs_ops = &au_sbi_ops, ++ .default_attrs = sysaufs_si_attrs ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int sysaufs_si_init(struct au_sbinfo *sbinfo) ++{ ++ int err; ++ ++ sbinfo->si_kobj.kset = sysaufs_kset; ++ /* cf. sysaufs_name() */ ++ err = kobject_init_and_add ++ (&sbinfo->si_kobj, &au_sbi_ktype, /*&sysaufs_kset->kobj*/NULL, ++ SysaufsSiNamePrefix "%lx", sysaufs_si_id(sbinfo)); ++ ++ return err; ++} ++ ++void sysaufs_fin(void) ++{ ++ sysfs_remove_group(&sysaufs_kset->kobj, sysaufs_attr_group); ++ kset_unregister(sysaufs_kset); ++} ++ ++int __init sysaufs_init(void) ++{ ++ int err; ++ ++ do { ++ get_random_bytes(&sysaufs_si_mask, sizeof(sysaufs_si_mask)); ++ } while (!sysaufs_si_mask); ++ ++ err = -EINVAL; ++ sysaufs_kset = kset_create_and_add(AUFS_NAME, NULL, fs_kobj); ++ if (unlikely(!sysaufs_kset)) ++ goto out; ++ err = PTR_ERR(sysaufs_kset); ++ if (IS_ERR(sysaufs_kset)) ++ goto out; ++ err = sysfs_create_group(&sysaufs_kset->kobj, sysaufs_attr_group); ++ if (unlikely(err)) ++ kset_unregister(sysaufs_kset); ++ ++out: ++ return err; ++} +diff -Naur null/fs/aufs/sysaufs.h linux-5.15.36/fs/aufs/sysaufs.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/sysaufs.h 2022-05-10 16:51:39.876744219 +0300 +@@ -0,0 +1,102 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * sysfs interface and mount lifetime management ++ */ ++ ++#ifndef __SYSAUFS_H__ ++#define __SYSAUFS_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "module.h" ++ ++struct super_block; ++struct au_sbinfo; ++ ++struct sysaufs_si_attr { ++ struct attribute attr; ++ int (*show)(struct seq_file *seq, struct super_block *sb); ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* sysaufs.c */ ++extern unsigned long sysaufs_si_mask; ++extern struct kset *sysaufs_kset; ++extern struct attribute *sysaufs_si_attrs[]; ++int sysaufs_si_init(struct au_sbinfo *sbinfo); ++int __init sysaufs_init(void); ++void sysaufs_fin(void); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* some people doesn't like to show a pointer in kernel */ ++static inline unsigned long sysaufs_si_id(struct au_sbinfo *sbinfo) ++{ ++ return sysaufs_si_mask ^ (unsigned long)sbinfo; ++} ++ ++#define SysaufsSiNamePrefix "si_" ++#define SysaufsSiNameLen (sizeof(SysaufsSiNamePrefix) + 16) ++static inline void sysaufs_name(struct au_sbinfo *sbinfo, char *name) ++{ ++ snprintf(name, SysaufsSiNameLen, SysaufsSiNamePrefix "%lx", ++ sysaufs_si_id(sbinfo)); ++} ++ ++struct au_branch; ++#ifdef CONFIG_SYSFS ++/* sysfs.c */ ++extern struct attribute_group *sysaufs_attr_group; ++ ++int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb); ++ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, ++ char *buf); ++long au_brinfo_ioctl(struct file *file, unsigned long arg); ++#ifdef CONFIG_COMPAT ++long au_brinfo_compat_ioctl(struct file *file, unsigned long arg); ++#endif ++ ++void sysaufs_br_init(struct au_branch *br); ++void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex); ++void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex); ++ ++#define sysaufs_brs_init() do {} while (0) ++ ++#else ++#define sysaufs_attr_group NULL ++ ++AuStubInt0(sysaufs_si_xi_path, struct seq_file *seq, struct super_block *sb) ++AuStub(ssize_t, sysaufs_si_show, return 0, struct kobject *kobj, ++ struct attribute *attr, char *buf) ++AuStubVoid(sysaufs_br_init, struct au_branch *br) ++AuStubVoid(sysaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex) ++AuStubVoid(sysaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex) ++ ++static inline void sysaufs_brs_init(void) ++{ ++ sysaufs_brs = 0; ++} ++ ++#endif /* CONFIG_SYSFS */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __SYSAUFS_H__ */ +diff -Naur null/fs/aufs/sysfs.c linux-5.15.36/fs/aufs/sysfs.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/sysfs.c 2022-05-10 16:51:39.876744219 +0300 +@@ -0,0 +1,374 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * sysfs interface ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++#ifdef CONFIG_AUFS_FS_MODULE ++/* this entry violates the "one line per file" policy of sysfs */ ++static ssize_t config_show(struct kobject *kobj, struct kobj_attribute *attr, ++ char *buf) ++{ ++ ssize_t err; ++ static char *conf = ++/* this file is generated at compiling */ ++#include "conf.str" ++ ; ++ ++ err = snprintf(buf, PAGE_SIZE, conf); ++ if (unlikely(err >= PAGE_SIZE)) ++ err = -EFBIG; ++ return err; ++} ++ ++static struct kobj_attribute au_config_attr = __ATTR_RO(config); ++#endif ++ ++static struct attribute *au_attr[] = { ++#ifdef CONFIG_AUFS_FS_MODULE ++ &au_config_attr.attr, ++#endif ++ NULL, /* need to NULL terminate the list of attributes */ ++}; ++ ++static struct attribute_group sysaufs_attr_group_body = { ++ .attrs = au_attr ++}; ++ ++struct attribute_group *sysaufs_attr_group = &sysaufs_attr_group_body; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb) ++{ ++ int err; ++ ++ SiMustAnyLock(sb); ++ ++ err = 0; ++ if (au_opt_test(au_mntflags(sb), XINO)) { ++ err = au_xino_path(seq, au_sbi(sb)->si_xib); ++ seq_putc(seq, '\n'); ++ } ++ return err; ++} ++ ++/* ++ * the lifetime of branch is independent from the entry under sysfs. ++ * sysfs handles the lifetime of the entry, and never call ->show() after it is ++ * unlinked. ++ */ ++static int sysaufs_si_br(struct seq_file *seq, struct super_block *sb, ++ aufs_bindex_t bindex, int idx) ++{ ++ int err; ++ struct path path; ++ struct dentry *root; ++ struct au_branch *br; ++ au_br_perm_str_t perm; ++ ++ AuDbg("b%d\n", bindex); ++ ++ err = 0; ++ root = sb->s_root; ++ di_read_lock_parent(root, !AuLock_IR); ++ br = au_sbr(sb, bindex); ++ ++ switch (idx) { ++ case AuBrSysfs_BR: ++ path.mnt = au_br_mnt(br); ++ path.dentry = au_h_dptr(root, bindex); ++ err = au_seq_path(seq, &path); ++ if (!err) { ++ au_optstr_br_perm(&perm, br->br_perm); ++ seq_printf(seq, "=%s\n", perm.a); ++ } ++ break; ++ case AuBrSysfs_BRID: ++ seq_printf(seq, "%d\n", br->br_id); ++ break; ++ } ++ di_read_unlock(root, !AuLock_IR); ++ if (unlikely(err || seq_has_overflowed(seq))) ++ err = -E2BIG; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct seq_file *au_seq(char *p, ssize_t len) ++{ ++ struct seq_file *seq; ++ ++ seq = kzalloc(sizeof(*seq), GFP_NOFS); ++ if (seq) { ++ /* mutex_init(&seq.lock); */ ++ seq->buf = p; ++ seq->size = len; ++ return seq; /* success */ ++ } ++ ++ seq = ERR_PTR(-ENOMEM); ++ return seq; ++} ++ ++#define SysaufsBr_PREFIX "br" ++#define SysaufsBrid_PREFIX "brid" ++ ++/* todo: file size may exceed PAGE_SIZE */ ++ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, ++ char *buf) ++{ ++ ssize_t err; ++ int idx; ++ long l; ++ aufs_bindex_t bbot; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ struct seq_file *seq; ++ char *name; ++ struct attribute **cattr; ++ ++ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); ++ sb = sbinfo->si_sb; ++ ++ /* ++ * prevent a race condition between sysfs and aufs. ++ * for instance, sysfs_file_read() calls sysfs_get_active_two() which ++ * prohibits maintaining the sysfs entries. ++ * hew we acquire read lock after sysfs_get_active_two(). ++ * on the other hand, the remount process may maintain the sysfs/aufs ++ * entries after acquiring write lock. ++ * it can cause a deadlock. ++ * simply we gave up processing read here. ++ */ ++ err = -EBUSY; ++ if (unlikely(!si_noflush_read_trylock(sb))) ++ goto out; ++ ++ seq = au_seq(buf, PAGE_SIZE); ++ err = PTR_ERR(seq); ++ if (IS_ERR(seq)) ++ goto out_unlock; ++ ++ name = (void *)attr->name; ++ cattr = sysaufs_si_attrs; ++ while (*cattr) { ++ if (!strcmp(name, (*cattr)->name)) { ++ err = container_of(*cattr, struct sysaufs_si_attr, attr) ++ ->show(seq, sb); ++ goto out_seq; ++ } ++ cattr++; ++ } ++ ++ if (!strncmp(name, SysaufsBrid_PREFIX, ++ sizeof(SysaufsBrid_PREFIX) - 1)) { ++ idx = AuBrSysfs_BRID; ++ name += sizeof(SysaufsBrid_PREFIX) - 1; ++ } else if (!strncmp(name, SysaufsBr_PREFIX, ++ sizeof(SysaufsBr_PREFIX) - 1)) { ++ idx = AuBrSysfs_BR; ++ name += sizeof(SysaufsBr_PREFIX) - 1; ++ } else ++ BUG(); ++ ++ err = kstrtol(name, 10, &l); ++ if (!err) { ++ bbot = au_sbbot(sb); ++ if (l <= bbot) ++ err = sysaufs_si_br(seq, sb, (aufs_bindex_t)l, idx); ++ else ++ err = -ENOENT; ++ } ++ ++out_seq: ++ if (!err) { ++ err = seq->count; ++ /* sysfs limit */ ++ if (unlikely(err == PAGE_SIZE)) ++ err = -EFBIG; ++ } ++ au_kfree_rcu(seq); ++out_unlock: ++ si_read_unlock(sb); ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_brinfo(struct super_block *sb, union aufs_brinfo __user *arg) ++{ ++ int err; ++ int16_t brid; ++ aufs_bindex_t bindex, bbot; ++ size_t sz; ++ char *buf; ++ struct seq_file *seq; ++ struct au_branch *br; ++ ++ si_read_lock(sb, AuLock_FLUSH); ++ bbot = au_sbbot(sb); ++ err = bbot + 1; ++ if (!arg) ++ goto out; ++ ++ err = -ENOMEM; ++ buf = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!buf)) ++ goto out; ++ ++ seq = au_seq(buf, PAGE_SIZE); ++ err = PTR_ERR(seq); ++ if (IS_ERR(seq)) ++ goto out_buf; ++ ++ sz = sizeof(*arg) - offsetof(union aufs_brinfo, path); ++ for (bindex = 0; bindex <= bbot; bindex++, arg++) { ++ /* VERIFY_WRITE */ ++ err = !access_ok(arg, sizeof(*arg)); ++ if (unlikely(err)) ++ break; ++ ++ br = au_sbr(sb, bindex); ++ brid = br->br_id; ++ BUILD_BUG_ON(sizeof(brid) != sizeof(arg->id)); ++ err = __put_user(brid, &arg->id); ++ if (unlikely(err)) ++ break; ++ ++ BUILD_BUG_ON(sizeof(br->br_perm) != sizeof(arg->perm)); ++ err = __put_user(br->br_perm, &arg->perm); ++ if (unlikely(err)) ++ break; ++ ++ err = au_seq_path(seq, &br->br_path); ++ if (unlikely(err)) ++ break; ++ seq_putc(seq, '\0'); ++ if (!seq_has_overflowed(seq)) { ++ err = copy_to_user(arg->path, seq->buf, seq->count); ++ seq->count = 0; ++ if (unlikely(err)) ++ break; ++ } else { ++ err = -E2BIG; ++ goto out_seq; ++ } ++ } ++ if (unlikely(err)) ++ err = -EFAULT; ++ ++out_seq: ++ au_kfree_rcu(seq); ++out_buf: ++ free_page((unsigned long)buf); ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++long au_brinfo_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_brinfo(file->f_path.dentry->d_sb, (void __user *)arg); ++} ++ ++#ifdef CONFIG_COMPAT ++long au_brinfo_compat_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_brinfo(file->f_path.dentry->d_sb, compat_ptr(arg)); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++void sysaufs_br_init(struct au_branch *br) ++{ ++ int i; ++ struct au_brsysfs *br_sysfs; ++ struct attribute *attr; ++ ++ br_sysfs = br->br_sysfs; ++ for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) { ++ attr = &br_sysfs->attr; ++ sysfs_attr_init(attr); ++ attr->name = br_sysfs->name; ++ attr->mode = 0444; ++ br_sysfs++; ++ } ++} ++ ++void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ struct au_branch *br; ++ struct kobject *kobj; ++ struct au_brsysfs *br_sysfs; ++ int i; ++ aufs_bindex_t bbot; ++ ++ if (!sysaufs_brs) ++ return; ++ ++ kobj = &au_sbi(sb)->si_kobj; ++ bbot = au_sbbot(sb); ++ for (; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ br_sysfs = br->br_sysfs; ++ for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) { ++ sysfs_remove_file(kobj, &br_sysfs->attr); ++ br_sysfs++; ++ } ++ } ++} ++ ++void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ int err, i; ++ aufs_bindex_t bbot; ++ struct kobject *kobj; ++ struct au_branch *br; ++ struct au_brsysfs *br_sysfs; ++ ++ if (!sysaufs_brs) ++ return; ++ ++ kobj = &au_sbi(sb)->si_kobj; ++ bbot = au_sbbot(sb); ++ for (; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ br_sysfs = br->br_sysfs; ++ snprintf(br_sysfs[AuBrSysfs_BR].name, sizeof(br_sysfs->name), ++ SysaufsBr_PREFIX "%d", bindex); ++ snprintf(br_sysfs[AuBrSysfs_BRID].name, sizeof(br_sysfs->name), ++ SysaufsBrid_PREFIX "%d", bindex); ++ for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) { ++ err = sysfs_create_file(kobj, &br_sysfs->attr); ++ if (unlikely(err)) ++ pr_warn("failed %s under sysfs(%d)\n", ++ br_sysfs->name, err); ++ br_sysfs++; ++ } ++ } ++} +diff -Naur null/fs/aufs/sysrq.c linux-5.15.36/fs/aufs/sysrq.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/sysrq.c 2022-05-10 16:51:39.877744219 +0300 +@@ -0,0 +1,149 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * magic sysrq handler ++ */ ++ ++/* #include */ ++#include ++#include "aufs.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void sysrq_sb(struct super_block *sb) ++{ ++ char *plevel; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ struct hlist_bl_head *files; ++ struct hlist_bl_node *pos; ++ struct au_finfo *finfo; ++ struct inode *i; ++ ++ plevel = au_plevel; ++ au_plevel = KERN_WARNING; ++ ++ /* since we define pr_fmt, call printk directly */ ++#define pr(str) printk(KERN_WARNING AUFS_NAME ": " str) ++ ++ sbinfo = au_sbi(sb); ++ printk(KERN_WARNING "si=%lx\n", sysaufs_si_id(sbinfo)); ++ pr("superblock\n"); ++ au_dpri_sb(sb); ++ ++#if 0 /* reserved */ ++ do { ++ int err, i, j, ndentry; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ ++ err = au_dpages_init(&dpages, GFP_ATOMIC); ++ if (unlikely(err)) ++ break; ++ err = au_dcsub_pages(&dpages, sb->s_root, NULL, NULL); ++ if (!err) ++ for (i = 0; i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ ndentry = dpage->ndentry; ++ for (j = 0; j < ndentry; j++) ++ au_dpri_dentry(dpage->dentries[j]); ++ } ++ au_dpages_free(&dpages); ++ } while (0); ++#endif ++ ++ pr("isolated inode\n"); ++ spin_lock(&sb->s_inode_list_lock); ++ list_for_each_entry(i, &sb->s_inodes, i_sb_list) { ++ spin_lock(&i->i_lock); ++ if (hlist_empty(&i->i_dentry)) ++ au_dpri_inode(i); ++ spin_unlock(&i->i_lock); ++ } ++ spin_unlock(&sb->s_inode_list_lock); ++ ++ pr("files\n"); ++ files = &au_sbi(sb)->si_files; ++ hlist_bl_lock(files); ++ hlist_bl_for_each_entry(finfo, pos, files, fi_hlist) { ++ umode_t mode; ++ ++ file = finfo->fi_file; ++ mode = file_inode(file)->i_mode; ++ if (!special_file(mode)) ++ au_dpri_file(file); ++ } ++ hlist_bl_unlock(files); ++ pr("done\n"); ++ ++#undef pr ++ au_plevel = plevel; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* module parameter */ ++static char *aufs_sysrq_key = "a"; ++module_param_named(sysrq, aufs_sysrq_key, charp, 0444); ++MODULE_PARM_DESC(sysrq, "MagicSysRq key for " AUFS_NAME); ++ ++static void au_sysrq(int key __maybe_unused) ++{ ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_node *pos; ++ ++ lockdep_off(); ++ au_sbilist_lock(); ++ hlist_bl_for_each_entry(sbinfo, pos, &au_sbilist, si_list) ++ sysrq_sb(sbinfo->si_sb); ++ au_sbilist_unlock(); ++ lockdep_on(); ++} ++ ++static struct sysrq_key_op au_sysrq_op = { ++ .handler = au_sysrq, ++ .help_msg = "Aufs", ++ .action_msg = "Aufs", ++ .enable_mask = SYSRQ_ENABLE_DUMP ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int __init au_sysrq_init(void) ++{ ++ int err; ++ char key; ++ ++ err = -1; ++ key = *aufs_sysrq_key; ++ if ('a' <= key && key <= 'z') ++ err = register_sysrq_key(key, &au_sysrq_op); ++ if (unlikely(err)) ++ pr_err("err %d, sysrq=%c\n", err, key); ++ return err; ++} ++ ++void au_sysrq_fin(void) ++{ ++ int err; ++ ++ err = unregister_sysrq_key(*aufs_sysrq_key, &au_sysrq_op); ++ if (unlikely(err)) ++ pr_err("err %d (ignored)\n", err); ++} +diff -Naur null/fs/aufs/vdir.c linux-5.15.36/fs/aufs/vdir.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/vdir.c 2022-05-10 16:51:39.877744219 +0300 +@@ -0,0 +1,896 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * virtual or vertical directory ++ */ ++ ++#include ++#include "aufs.h" ++ ++static unsigned int calc_size(int nlen) ++{ ++ return ALIGN(sizeof(struct au_vdir_de) + nlen, sizeof(ino_t)); ++} ++ ++static int set_deblk_end(union au_vdir_deblk_p *p, ++ union au_vdir_deblk_p *deblk_end) ++{ ++ if (calc_size(0) <= deblk_end->deblk - p->deblk) { ++ p->de->de_str.len = 0; ++ /* smp_mb(); */ ++ return 0; ++ } ++ return -1; /* error */ ++} ++ ++/* returns true or false */ ++static int is_deblk_end(union au_vdir_deblk_p *p, ++ union au_vdir_deblk_p *deblk_end) ++{ ++ if (calc_size(0) <= deblk_end->deblk - p->deblk) ++ return !p->de->de_str.len; ++ return 1; ++} ++ ++static unsigned char *last_deblk(struct au_vdir *vdir) ++{ ++ return vdir->vd_deblk[vdir->vd_nblk - 1]; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* estimate the appropriate size for name hash table */ ++unsigned int au_rdhash_est(loff_t sz) ++{ ++ unsigned int n; ++ ++ n = UINT_MAX; ++ sz >>= 10; ++ if (sz < n) ++ n = sz; ++ if (sz < AUFS_RDHASH_DEF) ++ n = AUFS_RDHASH_DEF; ++ /* pr_info("n %u\n", n); */ ++ return n; ++} ++ ++/* ++ * the allocated memory has to be freed by ++ * au_nhash_wh_free() or au_nhash_de_free(). ++ */ ++int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp) ++{ ++ struct hlist_head *head; ++ unsigned int u; ++ size_t sz; ++ ++ sz = sizeof(*nhash->nh_head) * num_hash; ++ head = kmalloc(sz, gfp); ++ if (head) { ++ nhash->nh_num = num_hash; ++ nhash->nh_head = head; ++ for (u = 0; u < num_hash; u++) ++ INIT_HLIST_HEAD(head++); ++ return 0; /* success */ ++ } ++ ++ return -ENOMEM; ++} ++ ++static void nhash_count(struct hlist_head *head) ++{ ++#if 0 /* debugging */ ++ unsigned long n; ++ struct hlist_node *pos; ++ ++ n = 0; ++ hlist_for_each(pos, head) ++ n++; ++ pr_info("%lu\n", n); ++#endif ++} ++ ++static void au_nhash_wh_do_free(struct hlist_head *head) ++{ ++ struct au_vdir_wh *pos; ++ struct hlist_node *node; ++ ++ hlist_for_each_entry_safe(pos, node, head, wh_hash) ++ au_kfree_rcu(pos); ++} ++ ++static void au_nhash_de_do_free(struct hlist_head *head) ++{ ++ struct au_vdir_dehstr *pos; ++ struct hlist_node *node; ++ ++ hlist_for_each_entry_safe(pos, node, head, hash) ++ au_cache_free_vdir_dehstr(pos); ++} ++ ++static void au_nhash_do_free(struct au_nhash *nhash, ++ void (*free)(struct hlist_head *head)) ++{ ++ unsigned int n; ++ struct hlist_head *head; ++ ++ n = nhash->nh_num; ++ if (!n) ++ return; ++ ++ head = nhash->nh_head; ++ while (n-- > 0) { ++ nhash_count(head); ++ free(head++); ++ } ++ au_kfree_try_rcu(nhash->nh_head); ++} ++ ++void au_nhash_wh_free(struct au_nhash *whlist) ++{ ++ au_nhash_do_free(whlist, au_nhash_wh_do_free); ++} ++ ++static void au_nhash_de_free(struct au_nhash *delist) ++{ ++ au_nhash_do_free(delist, au_nhash_de_do_free); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt, ++ int limit) ++{ ++ int num; ++ unsigned int u, n; ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ ++ num = 0; ++ n = whlist->nh_num; ++ head = whlist->nh_head; ++ for (u = 0; u < n; u++, head++) ++ hlist_for_each_entry(pos, head, wh_hash) ++ if (pos->wh_bindex == btgt && ++num > limit) ++ return 1; ++ return 0; ++} ++ ++static struct hlist_head *au_name_hash(struct au_nhash *nhash, ++ unsigned char *name, ++ unsigned int len) ++{ ++ unsigned int v; ++ /* const unsigned int magic_bit = 12; */ ++ ++ AuDebugOn(!nhash->nh_num || !nhash->nh_head); ++ ++ v = 0; ++ if (len > 8) ++ len = 8; ++ while (len--) ++ v += *name++; ++ /* v = hash_long(v, magic_bit); */ ++ v %= nhash->nh_num; ++ return nhash->nh_head + v; ++} ++ ++static int au_nhash_test_name(struct au_vdir_destr *str, const char *name, ++ int nlen) ++{ ++ return str->len == nlen && !memcmp(str->name, name, nlen); ++} ++ ++/* returns found or not */ ++int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen) ++{ ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ struct au_vdir_destr *str; ++ ++ head = au_name_hash(whlist, name, nlen); ++ hlist_for_each_entry(pos, head, wh_hash) { ++ str = &pos->wh_str; ++ AuDbg("%.*s\n", str->len, str->name); ++ if (au_nhash_test_name(str, name, nlen)) ++ return 1; ++ } ++ return 0; ++} ++ ++/* returns found(true) or not */ ++static int test_known(struct au_nhash *delist, char *name, int nlen) ++{ ++ struct hlist_head *head; ++ struct au_vdir_dehstr *pos; ++ struct au_vdir_destr *str; ++ ++ head = au_name_hash(delist, name, nlen); ++ hlist_for_each_entry(pos, head, hash) { ++ str = pos->str; ++ AuDbg("%.*s\n", str->len, str->name); ++ if (au_nhash_test_name(str, name, nlen)) ++ return 1; ++ } ++ return 0; ++} ++ ++static void au_shwh_init_wh(struct au_vdir_wh *wh, ino_t ino, ++ unsigned char d_type) ++{ ++#ifdef CONFIG_AUFS_SHWH ++ wh->wh_ino = ino; ++ wh->wh_type = d_type; ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino, ++ unsigned int d_type, aufs_bindex_t bindex, ++ unsigned char shwh) ++{ ++ int err; ++ struct au_vdir_destr *str; ++ struct au_vdir_wh *wh; ++ ++ AuDbg("%.*s\n", nlen, name); ++ AuDebugOn(!whlist->nh_num || !whlist->nh_head); ++ ++ err = -ENOMEM; ++ wh = kmalloc(sizeof(*wh) + nlen, GFP_NOFS); ++ if (unlikely(!wh)) ++ goto out; ++ ++ err = 0; ++ wh->wh_bindex = bindex; ++ if (shwh) ++ au_shwh_init_wh(wh, ino, d_type); ++ str = &wh->wh_str; ++ str->len = nlen; ++ memcpy(str->name, name, nlen); ++ hlist_add_head(&wh->wh_hash, au_name_hash(whlist, name, nlen)); ++ /* smp_mb(); */ ++ ++out: ++ return err; ++} ++ ++static int append_deblk(struct au_vdir *vdir) ++{ ++ int err; ++ unsigned long ul; ++ const unsigned int deblk_sz = vdir->vd_deblk_sz; ++ union au_vdir_deblk_p p, deblk_end; ++ unsigned char **o; ++ ++ err = -ENOMEM; ++ o = au_krealloc(vdir->vd_deblk, sizeof(*o) * (vdir->vd_nblk + 1), ++ GFP_NOFS, /*may_shrink*/0); ++ if (unlikely(!o)) ++ goto out; ++ ++ vdir->vd_deblk = o; ++ p.deblk = kmalloc(deblk_sz, GFP_NOFS); ++ if (p.deblk) { ++ ul = vdir->vd_nblk++; ++ vdir->vd_deblk[ul] = p.deblk; ++ vdir->vd_last.ul = ul; ++ vdir->vd_last.p.deblk = p.deblk; ++ deblk_end.deblk = p.deblk + deblk_sz; ++ err = set_deblk_end(&p, &deblk_end); ++ } ++ ++out: ++ return err; ++} ++ ++static int append_de(struct au_vdir *vdir, char *name, int nlen, ino_t ino, ++ unsigned int d_type, struct au_nhash *delist) ++{ ++ int err; ++ unsigned int sz; ++ const unsigned int deblk_sz = vdir->vd_deblk_sz; ++ union au_vdir_deblk_p p, *room, deblk_end; ++ struct au_vdir_dehstr *dehstr; ++ ++ p.deblk = last_deblk(vdir); ++ deblk_end.deblk = p.deblk + deblk_sz; ++ room = &vdir->vd_last.p; ++ AuDebugOn(room->deblk < p.deblk || deblk_end.deblk <= room->deblk ++ || !is_deblk_end(room, &deblk_end)); ++ ++ sz = calc_size(nlen); ++ if (unlikely(sz > deblk_end.deblk - room->deblk)) { ++ err = append_deblk(vdir); ++ if (unlikely(err)) ++ goto out; ++ ++ p.deblk = last_deblk(vdir); ++ deblk_end.deblk = p.deblk + deblk_sz; ++ /* smp_mb(); */ ++ AuDebugOn(room->deblk != p.deblk); ++ } ++ ++ err = -ENOMEM; ++ dehstr = au_cache_alloc_vdir_dehstr(); ++ if (unlikely(!dehstr)) ++ goto out; ++ ++ dehstr->str = &room->de->de_str; ++ hlist_add_head(&dehstr->hash, au_name_hash(delist, name, nlen)); ++ room->de->de_ino = ino; ++ room->de->de_type = d_type; ++ room->de->de_str.len = nlen; ++ memcpy(room->de->de_str.name, name, nlen); ++ ++ err = 0; ++ room->deblk += sz; ++ if (unlikely(set_deblk_end(room, &deblk_end))) ++ err = append_deblk(vdir); ++ /* smp_mb(); */ ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_vdir_free(struct au_vdir *vdir) ++{ ++ unsigned char **deblk; ++ ++ deblk = vdir->vd_deblk; ++ while (vdir->vd_nblk--) ++ au_kfree_try_rcu(*deblk++); ++ au_kfree_try_rcu(vdir->vd_deblk); ++ au_cache_free_vdir(vdir); ++} ++ ++static struct au_vdir *alloc_vdir(struct file *file) ++{ ++ struct au_vdir *vdir; ++ struct super_block *sb; ++ int err; ++ ++ sb = file->f_path.dentry->d_sb; ++ SiMustAnyLock(sb); ++ ++ err = -ENOMEM; ++ vdir = au_cache_alloc_vdir(); ++ if (unlikely(!vdir)) ++ goto out; ++ ++ vdir->vd_deblk = kzalloc(sizeof(*vdir->vd_deblk), GFP_NOFS); ++ if (unlikely(!vdir->vd_deblk)) ++ goto out_free; ++ ++ vdir->vd_deblk_sz = au_sbi(sb)->si_rdblk; ++ if (!vdir->vd_deblk_sz) { ++ /* estimate the appropriate size for deblk */ ++ vdir->vd_deblk_sz = au_dir_size(file, /*dentry*/NULL); ++ /* pr_info("vd_deblk_sz %u\n", vdir->vd_deblk_sz); */ ++ } ++ vdir->vd_nblk = 0; ++ vdir->vd_version = 0; ++ vdir->vd_jiffy = 0; ++ err = append_deblk(vdir); ++ if (!err) ++ return vdir; /* success */ ++ ++ au_kfree_try_rcu(vdir->vd_deblk); ++ ++out_free: ++ au_cache_free_vdir(vdir); ++out: ++ vdir = ERR_PTR(err); ++ return vdir; ++} ++ ++static int reinit_vdir(struct au_vdir *vdir) ++{ ++ int err; ++ union au_vdir_deblk_p p, deblk_end; ++ ++ while (vdir->vd_nblk > 1) { ++ au_kfree_try_rcu(vdir->vd_deblk[vdir->vd_nblk - 1]); ++ /* vdir->vd_deblk[vdir->vd_nblk - 1] = NULL; */ ++ vdir->vd_nblk--; ++ } ++ p.deblk = vdir->vd_deblk[0]; ++ deblk_end.deblk = p.deblk + vdir->vd_deblk_sz; ++ err = set_deblk_end(&p, &deblk_end); ++ /* keep vd_dblk_sz */ ++ vdir->vd_last.ul = 0; ++ vdir->vd_last.p.deblk = vdir->vd_deblk[0]; ++ vdir->vd_version = 0; ++ vdir->vd_jiffy = 0; ++ /* smp_mb(); */ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define AuFillVdir_CALLED 1 ++#define AuFillVdir_WHABLE (1 << 1) ++#define AuFillVdir_SHWH (1 << 2) ++#define au_ftest_fillvdir(flags, name) ((flags) & AuFillVdir_##name) ++#define au_fset_fillvdir(flags, name) \ ++ do { (flags) |= AuFillVdir_##name; } while (0) ++#define au_fclr_fillvdir(flags, name) \ ++ do { (flags) &= ~AuFillVdir_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_SHWH ++#undef AuFillVdir_SHWH ++#define AuFillVdir_SHWH 0 ++#endif ++ ++struct fillvdir_arg { ++ struct dir_context ctx; ++ struct file *file; ++ struct au_vdir *vdir; ++ struct au_nhash delist; ++ struct au_nhash whlist; ++ aufs_bindex_t bindex; ++ unsigned int flags; ++ int err; ++}; ++ ++static int fillvdir(struct dir_context *ctx, const char *__name, int nlen, ++ loff_t offset __maybe_unused, u64 h_ino, ++ unsigned int d_type) ++{ ++ struct fillvdir_arg *arg = container_of(ctx, struct fillvdir_arg, ctx); ++ char *name = (void *)__name; ++ struct super_block *sb; ++ ino_t ino; ++ const unsigned char shwh = !!au_ftest_fillvdir(arg->flags, SHWH); ++ ++ arg->err = 0; ++ sb = arg->file->f_path.dentry->d_sb; ++ au_fset_fillvdir(arg->flags, CALLED); ++ /* smp_mb(); */ ++ if (nlen <= AUFS_WH_PFX_LEN ++ || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { ++ if (test_known(&arg->delist, name, nlen) ++ || au_nhash_test_known_wh(&arg->whlist, name, nlen)) ++ goto out; /* already exists or whiteouted */ ++ ++ arg->err = au_ino(sb, arg->bindex, h_ino, d_type, &ino); ++ if (!arg->err) { ++ if (unlikely(nlen > AUFS_MAX_NAMELEN)) ++ d_type = DT_UNKNOWN; ++ arg->err = append_de(arg->vdir, name, nlen, ino, ++ d_type, &arg->delist); ++ } ++ } else if (au_ftest_fillvdir(arg->flags, WHABLE)) { ++ name += AUFS_WH_PFX_LEN; ++ nlen -= AUFS_WH_PFX_LEN; ++ if (au_nhash_test_known_wh(&arg->whlist, name, nlen)) ++ goto out; /* already whiteouted */ ++ ++ ino = 0; /* just to suppress a warning */ ++ if (shwh) ++ arg->err = au_wh_ino(sb, arg->bindex, h_ino, d_type, ++ &ino); ++ if (!arg->err) { ++ if (nlen <= AUFS_MAX_NAMELEN + AUFS_WH_PFX_LEN) ++ d_type = DT_UNKNOWN; ++ arg->err = au_nhash_append_wh ++ (&arg->whlist, name, nlen, ino, d_type, ++ arg->bindex, shwh); ++ } ++ } ++ ++out: ++ if (!arg->err) ++ arg->vdir->vd_jiffy = jiffies; ++ /* smp_mb(); */ ++ AuTraceErr(arg->err); ++ return arg->err; ++} ++ ++static int au_handle_shwh(struct super_block *sb, struct au_vdir *vdir, ++ struct au_nhash *whlist, struct au_nhash *delist) ++{ ++#ifdef CONFIG_AUFS_SHWH ++ int err; ++ unsigned int nh, u; ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ struct hlist_node *n; ++ char *p, *o; ++ struct au_vdir_destr *destr; ++ ++ AuDebugOn(!au_opt_test(au_mntflags(sb), SHWH)); ++ ++ err = -ENOMEM; ++ o = p = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!p)) ++ goto out; ++ ++ err = 0; ++ nh = whlist->nh_num; ++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); ++ p += AUFS_WH_PFX_LEN; ++ for (u = 0; u < nh; u++) { ++ head = whlist->nh_head + u; ++ hlist_for_each_entry_safe(pos, n, head, wh_hash) { ++ destr = &pos->wh_str; ++ memcpy(p, destr->name, destr->len); ++ err = append_de(vdir, o, destr->len + AUFS_WH_PFX_LEN, ++ pos->wh_ino, pos->wh_type, delist); ++ if (unlikely(err)) ++ break; ++ } ++ } ++ ++ free_page((unsigned long)o); ++ ++out: ++ AuTraceErr(err); ++ return err; ++#else ++ return 0; ++#endif ++} ++ ++static int au_do_read_vdir(struct fillvdir_arg *arg) ++{ ++ int err; ++ unsigned int rdhash; ++ loff_t offset; ++ aufs_bindex_t bbot, bindex, btop; ++ unsigned char shwh; ++ struct file *hf, *file; ++ struct super_block *sb; ++ ++ file = arg->file; ++ sb = file->f_path.dentry->d_sb; ++ SiMustAnyLock(sb); ++ ++ rdhash = au_sbi(sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(file, /*dentry*/NULL)); ++ err = au_nhash_alloc(&arg->delist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_nhash_alloc(&arg->whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out_delist; ++ ++ err = 0; ++ arg->flags = 0; ++ shwh = 0; ++ if (au_opt_test(au_mntflags(sb), SHWH)) { ++ shwh = 1; ++ au_fset_fillvdir(arg->flags, SHWH); ++ } ++ btop = au_fbtop(file); ++ bbot = au_fbbot_dir(file); ++ for (bindex = btop; !err && bindex <= bbot; bindex++) { ++ hf = au_hf_dir(file, bindex); ++ if (!hf) ++ continue; ++ ++ offset = vfsub_llseek(hf, 0, SEEK_SET); ++ err = offset; ++ if (unlikely(offset)) ++ break; ++ ++ arg->bindex = bindex; ++ au_fclr_fillvdir(arg->flags, WHABLE); ++ if (shwh ++ || (bindex != bbot ++ && au_br_whable(au_sbr_perm(sb, bindex)))) ++ au_fset_fillvdir(arg->flags, WHABLE); ++ do { ++ arg->err = 0; ++ au_fclr_fillvdir(arg->flags, CALLED); ++ /* smp_mb(); */ ++ err = vfsub_iterate_dir(hf, &arg->ctx); ++ if (err >= 0) ++ err = arg->err; ++ } while (!err && au_ftest_fillvdir(arg->flags, CALLED)); ++ ++ /* ++ * dir_relax() may be good for concurrency, but aufs should not ++ * use it since it will cause a lockdep problem. ++ */ ++ } ++ ++ if (!err && shwh) ++ err = au_handle_shwh(sb, arg->vdir, &arg->whlist, &arg->delist); ++ ++ au_nhash_wh_free(&arg->whlist); ++ ++out_delist: ++ au_nhash_de_free(&arg->delist); ++out: ++ return err; ++} ++ ++static int read_vdir(struct file *file, int may_read) ++{ ++ int err; ++ unsigned long expire; ++ unsigned char do_read; ++ struct fillvdir_arg arg = { ++ .ctx = { ++ .actor = fillvdir ++ } ++ }; ++ struct inode *inode; ++ struct au_vdir *vdir, *allocated; ++ ++ err = 0; ++ inode = file_inode(file); ++ IMustLock(inode); ++ IiMustWriteLock(inode); ++ SiMustAnyLock(inode->i_sb); ++ ++ allocated = NULL; ++ do_read = 0; ++ expire = au_sbi(inode->i_sb)->si_rdcache; ++ vdir = au_ivdir(inode); ++ if (!vdir) { ++ do_read = 1; ++ vdir = alloc_vdir(file); ++ err = PTR_ERR(vdir); ++ if (IS_ERR(vdir)) ++ goto out; ++ err = 0; ++ allocated = vdir; ++ } else if (may_read ++ && (!inode_eq_iversion(inode, vdir->vd_version) ++ || time_after(jiffies, vdir->vd_jiffy + expire))) { ++ do_read = 1; ++ err = reinit_vdir(vdir); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ if (!do_read) ++ return 0; /* success */ ++ ++ arg.file = file; ++ arg.vdir = vdir; ++ err = au_do_read_vdir(&arg); ++ if (!err) { ++ /* file->f_pos = 0; */ /* todo: ctx->pos? */ ++ vdir->vd_version = inode_query_iversion(inode); ++ vdir->vd_last.ul = 0; ++ vdir->vd_last.p.deblk = vdir->vd_deblk[0]; ++ if (allocated) ++ au_set_ivdir(inode, allocated); ++ } else if (allocated) ++ au_vdir_free(allocated); ++ ++out: ++ return err; ++} ++ ++static int copy_vdir(struct au_vdir *tgt, struct au_vdir *src) ++{ ++ int err, rerr; ++ unsigned long ul, n; ++ const unsigned int deblk_sz = src->vd_deblk_sz; ++ ++ AuDebugOn(tgt->vd_nblk != 1); ++ ++ err = -ENOMEM; ++ if (tgt->vd_nblk < src->vd_nblk) { ++ unsigned char **p; ++ ++ p = au_krealloc(tgt->vd_deblk, sizeof(*p) * src->vd_nblk, ++ GFP_NOFS, /*may_shrink*/0); ++ if (unlikely(!p)) ++ goto out; ++ tgt->vd_deblk = p; ++ } ++ ++ if (tgt->vd_deblk_sz != deblk_sz) { ++ unsigned char *p; ++ ++ tgt->vd_deblk_sz = deblk_sz; ++ p = au_krealloc(tgt->vd_deblk[0], deblk_sz, GFP_NOFS, ++ /*may_shrink*/1); ++ if (unlikely(!p)) ++ goto out; ++ tgt->vd_deblk[0] = p; ++ } ++ memcpy(tgt->vd_deblk[0], src->vd_deblk[0], deblk_sz); ++ tgt->vd_version = src->vd_version; ++ tgt->vd_jiffy = src->vd_jiffy; ++ ++ n = src->vd_nblk; ++ for (ul = 1; ul < n; ul++) { ++ tgt->vd_deblk[ul] = kmemdup(src->vd_deblk[ul], deblk_sz, ++ GFP_NOFS); ++ if (unlikely(!tgt->vd_deblk[ul])) ++ goto out; ++ tgt->vd_nblk++; ++ } ++ tgt->vd_nblk = n; ++ tgt->vd_last.ul = tgt->vd_last.ul; ++ tgt->vd_last.p.deblk = tgt->vd_deblk[tgt->vd_last.ul]; ++ tgt->vd_last.p.deblk += src->vd_last.p.deblk ++ - src->vd_deblk[src->vd_last.ul]; ++ /* smp_mb(); */ ++ return 0; /* success */ ++ ++out: ++ rerr = reinit_vdir(tgt); ++ BUG_ON(rerr); ++ return err; ++} ++ ++int au_vdir_init(struct file *file) ++{ ++ int err; ++ struct inode *inode; ++ struct au_vdir *vdir_cache, *allocated; ++ ++ /* test file->f_pos here instead of ctx->pos */ ++ err = read_vdir(file, !file->f_pos); ++ if (unlikely(err)) ++ goto out; ++ ++ allocated = NULL; ++ vdir_cache = au_fvdir_cache(file); ++ if (!vdir_cache) { ++ vdir_cache = alloc_vdir(file); ++ err = PTR_ERR(vdir_cache); ++ if (IS_ERR(vdir_cache)) ++ goto out; ++ allocated = vdir_cache; ++ } else if (!file->f_pos && vdir_cache->vd_version != file->f_version) { ++ /* test file->f_pos here instead of ctx->pos */ ++ err = reinit_vdir(vdir_cache); ++ if (unlikely(err)) ++ goto out; ++ } else ++ return 0; /* success */ ++ ++ inode = file_inode(file); ++ err = copy_vdir(vdir_cache, au_ivdir(inode)); ++ if (!err) { ++ file->f_version = inode_query_iversion(inode); ++ if (allocated) ++ au_set_fvdir_cache(file, allocated); ++ } else if (allocated) ++ au_vdir_free(allocated); ++ ++out: ++ return err; ++} ++ ++static loff_t calc_offset(struct au_vdir *vdir) ++{ ++ loff_t offset; ++ union au_vdir_deblk_p p; ++ ++ p.deblk = vdir->vd_deblk[vdir->vd_last.ul]; ++ offset = vdir->vd_last.p.deblk - p.deblk; ++ offset += vdir->vd_deblk_sz * vdir->vd_last.ul; ++ return offset; ++} ++ ++/* returns true or false */ ++static int seek_vdir(struct file *file, struct dir_context *ctx) ++{ ++ int valid; ++ unsigned int deblk_sz; ++ unsigned long ul, n; ++ loff_t offset; ++ union au_vdir_deblk_p p, deblk_end; ++ struct au_vdir *vdir_cache; ++ ++ valid = 1; ++ vdir_cache = au_fvdir_cache(file); ++ offset = calc_offset(vdir_cache); ++ AuDbg("offset %lld\n", offset); ++ if (ctx->pos == offset) ++ goto out; ++ ++ vdir_cache->vd_last.ul = 0; ++ vdir_cache->vd_last.p.deblk = vdir_cache->vd_deblk[0]; ++ if (!ctx->pos) ++ goto out; ++ ++ valid = 0; ++ deblk_sz = vdir_cache->vd_deblk_sz; ++ ul = div64_u64(ctx->pos, deblk_sz); ++ AuDbg("ul %lu\n", ul); ++ if (ul >= vdir_cache->vd_nblk) ++ goto out; ++ ++ n = vdir_cache->vd_nblk; ++ for (; ul < n; ul++) { ++ p.deblk = vdir_cache->vd_deblk[ul]; ++ deblk_end.deblk = p.deblk + deblk_sz; ++ offset = ul; ++ offset *= deblk_sz; ++ while (!is_deblk_end(&p, &deblk_end) && offset < ctx->pos) { ++ unsigned int l; ++ ++ l = calc_size(p.de->de_str.len); ++ offset += l; ++ p.deblk += l; ++ } ++ if (!is_deblk_end(&p, &deblk_end)) { ++ valid = 1; ++ vdir_cache->vd_last.ul = ul; ++ vdir_cache->vd_last.p = p; ++ break; ++ } ++ } ++ ++out: ++ /* smp_mb(); */ ++ if (!valid) ++ AuDbg("valid %d\n", !valid); ++ return valid; ++} ++ ++int au_vdir_fill_de(struct file *file, struct dir_context *ctx) ++{ ++ unsigned int l, deblk_sz; ++ union au_vdir_deblk_p deblk_end; ++ struct au_vdir *vdir_cache; ++ struct au_vdir_de *de; ++ ++ if (!seek_vdir(file, ctx)) ++ return 0; ++ ++ vdir_cache = au_fvdir_cache(file); ++ deblk_sz = vdir_cache->vd_deblk_sz; ++ while (1) { ++ deblk_end.deblk = vdir_cache->vd_deblk[vdir_cache->vd_last.ul]; ++ deblk_end.deblk += deblk_sz; ++ while (!is_deblk_end(&vdir_cache->vd_last.p, &deblk_end)) { ++ de = vdir_cache->vd_last.p.de; ++ AuDbg("%.*s, off%lld, i%lu, dt%d\n", ++ de->de_str.len, de->de_str.name, ctx->pos, ++ (unsigned long)de->de_ino, de->de_type); ++ if (unlikely(!dir_emit(ctx, de->de_str.name, ++ de->de_str.len, de->de_ino, ++ de->de_type))) { ++ /* todo: ignore the error caused by udba? */ ++ /* return err; */ ++ return 0; ++ } ++ ++ l = calc_size(de->de_str.len); ++ vdir_cache->vd_last.p.deblk += l; ++ ctx->pos += l; ++ } ++ if (vdir_cache->vd_last.ul < vdir_cache->vd_nblk - 1) { ++ vdir_cache->vd_last.ul++; ++ vdir_cache->vd_last.p.deblk ++ = vdir_cache->vd_deblk[vdir_cache->vd_last.ul]; ++ ctx->pos = deblk_sz * vdir_cache->vd_last.ul; ++ continue; ++ } ++ break; ++ } ++ ++ /* smp_mb(); */ ++ return 0; ++} +diff -Naur null/fs/aufs/vfsub.c linux-5.15.36/fs/aufs/vfsub.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/vfsub.c 2022-05-10 16:51:39.877744219 +0300 +@@ -0,0 +1,918 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * sub-routines for VFS ++ */ ++ ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++#ifdef CONFIG_AUFS_BR_FUSE ++int vfsub_test_mntns(struct vfsmount *mnt, struct super_block *h_sb) ++{ ++ if (!au_test_fuse(h_sb) || !au_userns) ++ return 0; ++ ++ return is_current_mnt_ns(mnt) ? 0 : -EACCES; ++} ++#endif ++ ++int vfsub_sync_filesystem(struct super_block *h_sb) ++{ ++ int err; ++ ++ lockdep_off(); ++ down_read(&h_sb->s_umount); ++ err = sync_filesystem(h_sb); ++ up_read(&h_sb->s_umount); ++ lockdep_on(); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int vfsub_update_h_iattr(struct path *h_path, int *did) ++{ ++ int err; ++ struct kstat st; ++ struct super_block *h_sb; ++ ++ /* ++ * Always needs h_path->mnt for LSM or FUSE branch. ++ */ ++ AuDebugOn(!h_path->mnt); ++ ++ /* for remote fs, leave work for its getattr or d_revalidate */ ++ /* for bad i_attr fs, handle them in aufs_getattr() */ ++ /* still some fs may acquire i_mutex. we need to skip them */ ++ err = 0; ++ if (!did) ++ did = &err; ++ h_sb = h_path->dentry->d_sb; ++ *did = (!au_test_fs_remote(h_sb) && au_test_fs_refresh_iattr(h_sb)); ++ if (*did) ++ err = vfsub_getattr(h_path, &st); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct file *vfsub_dentry_open(struct path *path, int flags) ++{ ++ return dentry_open(path, flags /* | __FMODE_NONOTIFY */, ++ current_cred()); ++} ++ ++struct file *vfsub_filp_open(const char *path, int oflags, int mode) ++{ ++ struct file *file; ++ ++ lockdep_off(); ++ file = filp_open(path, ++ oflags /* | __FMODE_NONOTIFY */, ++ mode); ++ lockdep_on(); ++ if (IS_ERR(file)) ++ goto out; ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ ++out: ++ return file; ++} ++ ++/* ++ * Ideally this function should call VFS:do_last() in order to keep all its ++ * checkings. But it is very hard for aufs to regenerate several VFS internal ++ * structure such as nameidata. This is a second (or third) best approach. ++ * cf. linux/fs/namei.c:do_last(), lookup_open() and atomic_open(). ++ */ ++int vfsub_atomic_open(struct inode *dir, struct dentry *dentry, ++ struct vfsub_aopen_args *args) ++{ ++ int err; ++ struct au_branch *br = args->br; ++ struct file *file = args->file; ++ /* copied from linux/fs/namei.c:atomic_open() */ ++ struct dentry *const DENTRY_NOT_SET = (void *)-1UL; ++ ++ IMustLock(dir); ++ AuDebugOn(!dir->i_op->atomic_open); ++ ++ err = au_br_test_oflag(args->open_flag, br); ++ if (unlikely(err)) ++ goto out; ++ ++ au_lcnt_inc(&br->br_nfiles); ++ file->f_path.dentry = DENTRY_NOT_SET; ++ file->f_path.mnt = au_br_mnt(br); ++ AuDbg("%ps\n", dir->i_op->atomic_open); ++ err = dir->i_op->atomic_open(dir, dentry, file, args->open_flag, ++ args->create_mode); ++ if (unlikely(err < 0)) { ++ au_lcnt_dec(&br->br_nfiles); ++ goto out; ++ } ++ ++ /* temporary workaround for nfsv4 branch */ ++ if (au_test_nfs(dir->i_sb)) ++ nfs_mark_for_revalidate(dir); ++ ++ if (file->f_mode & FMODE_CREATED) ++ fsnotify_create(dir, dentry); ++ if (!(file->f_mode & FMODE_OPENED)) { ++ au_lcnt_dec(&br->br_nfiles); ++ goto out; ++ } ++ ++ /* todo: call VFS:may_open() here */ ++ /* todo: ima_file_check() too? */ ++ if (!err && (args->open_flag & __FMODE_EXEC)) ++ err = deny_write_access(file); ++ if (!err) ++ fsnotify_open(file); ++ else ++ au_lcnt_dec(&br->br_nfiles); ++ /* note that the file is created and still opened */ ++ ++out: ++ return err; ++} ++ ++int vfsub_kern_path(const char *name, unsigned int flags, struct path *path) ++{ ++ int err; ++ ++ err = kern_path(name, flags, path); ++ if (!err && d_is_positive(path->dentry)) ++ vfsub_update_h_iattr(path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++struct dentry *vfsub_lookup_one_len_unlocked(const char *name, ++ struct path *ppath, int len) ++{ ++ struct path path; ++ ++ path.dentry = lookup_one_len_unlocked(name, ppath->dentry, len); ++ if (IS_ERR(path.dentry)) ++ goto out; ++ if (d_is_positive(path.dentry)) { ++ path.mnt = ppath->mnt; ++ vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/ ++ } ++ ++out: ++ AuTraceErrPtr(path.dentry); ++ return path.dentry; ++} ++ ++struct dentry *vfsub_lookup_one_len(const char *name, struct path *ppath, ++ int len) ++{ ++ struct path path; ++ ++ /* VFS checks it too, but by WARN_ON_ONCE() */ ++ IMustLock(d_inode(ppath->dentry)); ++ ++ path.dentry = lookup_one_len(name, ppath->dentry, len); ++ if (IS_ERR(path.dentry)) ++ goto out; ++ if (d_is_positive(path.dentry)) { ++ path.mnt = ppath->mnt; ++ vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/ ++ } ++ ++out: ++ AuTraceErrPtr(path.dentry); ++ return path.dentry; ++} ++ ++void vfsub_call_lkup_one(void *args) ++{ ++ struct vfsub_lkup_one_args *a = args; ++ *a->errp = vfsub_lkup_one(a->name, a->ppath); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1, ++ struct dentry *d2, struct au_hinode *hdir2) ++{ ++ struct dentry *d; ++ ++ lockdep_off(); ++ d = lock_rename(d1, d2); ++ lockdep_on(); ++ au_hn_suspend(hdir1); ++ if (hdir1 != hdir2) ++ au_hn_suspend(hdir2); ++ ++ return d; ++} ++ ++void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1, ++ struct dentry *d2, struct au_hinode *hdir2) ++{ ++ au_hn_resume(hdir1); ++ if (hdir1 != hdir2) ++ au_hn_resume(hdir2); ++ lockdep_off(); ++ unlock_rename(d1, d2); ++ lockdep_on(); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int vfsub_create(struct inode *dir, struct path *path, int mode, bool want_excl) ++{ ++ int err; ++ struct dentry *d; ++ struct user_namespace *userns; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_mknod(path, d, mode, 0); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ userns = mnt_user_ns(path->mnt); ++ ++ lockdep_off(); ++ err = vfs_create(userns, dir, path->dentry, mode, want_excl); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++int vfsub_symlink(struct inode *dir, struct path *path, const char *symname) ++{ ++ int err; ++ struct dentry *d; ++ struct user_namespace *userns; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_symlink(path, d, symname); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ userns = mnt_user_ns(path->mnt); ++ ++ lockdep_off(); ++ err = vfs_symlink(userns, dir, path->dentry, symname); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev) ++{ ++ int err; ++ struct dentry *d; ++ struct user_namespace *userns; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_mknod(path, d, mode, new_encode_dev(dev)); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ userns = mnt_user_ns(path->mnt); ++ ++ lockdep_off(); ++ err = vfs_mknod(userns, dir, path->dentry, mode, dev); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++static int au_test_nlink(struct inode *inode) ++{ ++ const unsigned int link_max = UINT_MAX >> 1; /* rough margin */ ++ ++ if (!au_test_fs_no_limit_nlink(inode->i_sb) ++ || inode->i_nlink < link_max) ++ return 0; ++ return -EMLINK; ++} ++ ++int vfsub_link(struct dentry *src_dentry, struct inode *dir, struct path *path, ++ struct inode **delegated_inode) ++{ ++ int err; ++ struct dentry *d; ++ struct user_namespace *userns; ++ ++ IMustLock(dir); ++ ++ err = au_test_nlink(d_inode(src_dentry)); ++ if (unlikely(err)) ++ return err; ++ ++ /* we don't call may_linkat() */ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_link(src_dentry, path, d); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ userns = mnt_user_ns(path->mnt); ++ ++ lockdep_off(); ++ err = vfs_link(src_dentry, userns, dir, path->dentry, delegated_inode); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ /* fuse has different memory inode for the same inumber */ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ tmp.dentry = src_dentry; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++int vfsub_rename(struct inode *src_dir, struct dentry *src_dentry, ++ struct inode *dir, struct path *path, ++ struct inode **delegated_inode, unsigned int flags) ++{ ++ int err; ++ struct renamedata rd; ++ struct path tmp = { ++ .mnt = path->mnt ++ }; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ IMustLock(src_dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ tmp.dentry = src_dentry->d_parent; ++ err = security_path_rename(&tmp, src_dentry, path, d, /*flags*/0); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ rd.old_mnt_userns = mnt_user_ns(path->mnt); ++ rd.old_dir = src_dir; ++ rd.old_dentry = src_dentry; ++ rd.new_mnt_userns = rd.old_mnt_userns; ++ rd.new_dir = dir; ++ rd.new_dentry = path->dentry; ++ rd.delegated_inode = delegated_inode; ++ rd.flags = flags; ++ lockdep_off(); ++ err = vfs_rename(&rd); ++ lockdep_on(); ++ if (!err) { ++ int did; ++ ++ tmp.dentry = d->d_parent; ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = src_dentry; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ tmp.dentry = src_dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++int vfsub_mkdir(struct inode *dir, struct path *path, int mode) ++{ ++ int err; ++ struct dentry *d; ++ struct user_namespace *userns; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_mkdir(path, d, mode); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ userns = mnt_user_ns(path->mnt); ++ ++ lockdep_off(); ++ err = vfs_mkdir(userns, dir, path->dentry, mode); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++int vfsub_rmdir(struct inode *dir, struct path *path) ++{ ++ int err; ++ struct dentry *d; ++ struct user_namespace *userns; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_rmdir(path, d); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ userns = mnt_user_ns(path->mnt); ++ ++ lockdep_off(); ++ err = vfs_rmdir(userns, dir, path->dentry); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = { ++ .dentry = path->dentry->d_parent, ++ .mnt = path->mnt ++ }; ++ ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* todo: support mmap_sem? */ ++ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ ++ lockdep_off(); ++ err = vfs_read(file, ubuf, count, ppos); ++ lockdep_on(); ++ if (err >= 0) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ ++ lockdep_off(); ++ err = kernel_read(file, kbuf, count, ppos); ++ lockdep_on(); ++ AuTraceErr(err); ++ if (err >= 0) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ ++ lockdep_off(); ++ err = vfs_write(file, ubuf, count, ppos); ++ lockdep_on(); ++ if (err >= 0) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, loff_t *ppos) ++{ ++ ssize_t err; ++ ++ lockdep_off(); ++ err = kernel_write(file, kbuf, count, ppos); ++ lockdep_on(); ++ if (err >= 0) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++int vfsub_flush(struct file *file, fl_owner_t id) ++{ ++ int err; ++ ++ err = 0; ++ if (file->f_op->flush) { ++ if (!au_test_nfs(file->f_path.dentry->d_sb)) ++ err = file->f_op->flush(file, id); ++ else { ++ lockdep_off(); ++ err = file->f_op->flush(file, id); ++ lockdep_on(); ++ } ++ if (!err) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); ++ /*ignore*/ ++ } ++ return err; ++} ++ ++int vfsub_iterate_dir(struct file *file, struct dir_context *ctx) ++{ ++ int err; ++ ++ AuDbg("%pD, ctx{%ps, %llu}\n", file, ctx->actor, ctx->pos); ++ ++ lockdep_off(); ++ err = iterate_dir(file, ctx); ++ lockdep_on(); ++ if (err >= 0) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ ++ return err; ++} ++ ++long vfsub_splice_to(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags) ++{ ++ long err; ++ ++ lockdep_off(); ++ err = do_splice_to(in, ppos, pipe, len, flags); ++ lockdep_on(); ++ file_accessed(in); ++ if (err >= 0) ++ vfsub_update_h_iattr(&in->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags) ++{ ++ long err; ++ ++ lockdep_off(); ++ err = do_splice_from(pipe, out, ppos, len, flags); ++ lockdep_on(); ++ if (err >= 0) ++ vfsub_update_h_iattr(&out->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++int vfsub_fsync(struct file *file, struct path *path, int datasync) ++{ ++ int err; ++ ++ /* file can be NULL */ ++ lockdep_off(); ++ err = vfs_fsync(file, datasync); ++ lockdep_on(); ++ if (!err) { ++ if (!path) { ++ AuDebugOn(!file); ++ path = &file->f_path; ++ } ++ vfsub_update_h_iattr(path, /*did*/NULL); /*ignore*/ ++ } ++ return err; ++} ++ ++/* cf. open.c:do_sys_truncate() and do_sys_ftruncate() */ ++int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr, ++ struct file *h_file) ++{ ++ int err; ++ struct inode *h_inode; ++ struct super_block *h_sb; ++ struct user_namespace *h_userns; ++ ++ if (!h_file) { ++ err = vfsub_truncate(h_path, length); ++ goto out; ++ } ++ ++ h_inode = d_inode(h_path->dentry); ++ h_sb = h_inode->i_sb; ++ lockdep_off(); ++ sb_start_write(h_sb); ++ lockdep_on(); ++ err = security_path_truncate(h_path); ++ if (!err) { ++ h_userns = mnt_user_ns(h_path->mnt); ++ lockdep_off(); ++ err = do_truncate(h_userns, h_path->dentry, length, attr, ++ h_file); ++ lockdep_on(); ++ } ++ lockdep_off(); ++ sb_end_write(h_sb); ++ lockdep_on(); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_vfsub_mkdir_args { ++ int *errp; ++ struct inode *dir; ++ struct path *path; ++ int mode; ++}; ++ ++static void au_call_vfsub_mkdir(void *args) ++{ ++ struct au_vfsub_mkdir_args *a = args; ++ *a->errp = vfsub_mkdir(a->dir, a->path, a->mode); ++} ++ ++int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode) ++{ ++ int err, do_sio, wkq_err; ++ struct user_namespace *userns; ++ ++ userns = mnt_user_ns(path->mnt); ++ do_sio = au_test_h_perm_sio(userns, dir, MAY_EXEC | MAY_WRITE); ++ if (!do_sio) { ++ lockdep_off(); ++ err = vfsub_mkdir(dir, path, mode); ++ lockdep_on(); ++ } else { ++ struct au_vfsub_mkdir_args args = { ++ .errp = &err, ++ .dir = dir, ++ .path = path, ++ .mode = mode ++ }; ++ wkq_err = au_wkq_wait(au_call_vfsub_mkdir, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ return err; ++} ++ ++struct au_vfsub_rmdir_args { ++ int *errp; ++ struct inode *dir; ++ struct path *path; ++}; ++ ++static void au_call_vfsub_rmdir(void *args) ++{ ++ struct au_vfsub_rmdir_args *a = args; ++ *a->errp = vfsub_rmdir(a->dir, a->path); ++} ++ ++int vfsub_sio_rmdir(struct inode *dir, struct path *path) ++{ ++ int err, do_sio, wkq_err; ++ struct user_namespace *userns; ++ ++ userns = mnt_user_ns(path->mnt); ++ do_sio = au_test_h_perm_sio(userns, dir, MAY_EXEC | MAY_WRITE); ++ if (!do_sio) { ++ lockdep_off(); ++ err = vfsub_rmdir(dir, path); ++ lockdep_on(); ++ } else { ++ struct au_vfsub_rmdir_args args = { ++ .errp = &err, ++ .dir = dir, ++ .path = path ++ }; ++ wkq_err = au_wkq_wait(au_call_vfsub_rmdir, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct notify_change_args { ++ int *errp; ++ struct path *path; ++ struct iattr *ia; ++ struct inode **delegated_inode; ++}; ++ ++static void call_notify_change(void *args) ++{ ++ struct notify_change_args *a = args; ++ struct inode *h_inode; ++ struct user_namespace *userns; ++ ++ h_inode = d_inode(a->path->dentry); ++ IMustLock(h_inode); ++ ++ *a->errp = -EPERM; ++ if (!IS_IMMUTABLE(h_inode) && !IS_APPEND(h_inode)) { ++ userns = mnt_user_ns(a->path->mnt); ++ lockdep_off(); ++ *a->errp = notify_change(userns, a->path->dentry, a->ia, ++ a->delegated_inode); ++ lockdep_on(); ++ if (!*a->errp) ++ vfsub_update_h_iattr(a->path, /*did*/NULL); /*ignore*/ ++ } ++ AuTraceErr(*a->errp); ++} ++ ++int vfsub_notify_change(struct path *path, struct iattr *ia, ++ struct inode **delegated_inode) ++{ ++ int err; ++ struct notify_change_args args = { ++ .errp = &err, ++ .path = path, ++ .ia = ia, ++ .delegated_inode = delegated_inode ++ }; ++ ++ call_notify_change(&args); ++ ++ return err; ++} ++ ++int vfsub_sio_notify_change(struct path *path, struct iattr *ia, ++ struct inode **delegated_inode) ++{ ++ int err, wkq_err; ++ struct notify_change_args args = { ++ .errp = &err, ++ .path = path, ++ .ia = ia, ++ .delegated_inode = delegated_inode ++ }; ++ ++ wkq_err = au_wkq_wait(call_notify_change, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct unlink_args { ++ int *errp; ++ struct inode *dir; ++ struct path *path; ++ struct inode **delegated_inode; ++}; ++ ++static void call_unlink(void *args) ++{ ++ struct unlink_args *a = args; ++ struct dentry *d = a->path->dentry; ++ struct inode *h_inode; ++ struct user_namespace *userns; ++ const int stop_sillyrename = (au_test_nfs(d->d_sb) ++ && au_dcount(d) == 1); ++ ++ IMustLock(a->dir); ++ ++ a->path->dentry = d->d_parent; ++ *a->errp = security_path_unlink(a->path, d); ++ a->path->dentry = d; ++ if (unlikely(*a->errp)) ++ return; ++ ++ if (!stop_sillyrename) ++ dget(d); ++ h_inode = NULL; ++ if (d_is_positive(d)) { ++ h_inode = d_inode(d); ++ ihold(h_inode); ++ } ++ ++ userns = mnt_user_ns(a->path->mnt); ++ lockdep_off(); ++ *a->errp = vfs_unlink(userns, a->dir, d, a->delegated_inode); ++ lockdep_on(); ++ if (!*a->errp) { ++ struct path tmp = { ++ .dentry = d->d_parent, ++ .mnt = a->path->mnt ++ }; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/ ++ } ++ ++ if (!stop_sillyrename) ++ dput(d); ++ if (h_inode) ++ iput(h_inode); ++ ++ AuTraceErr(*a->errp); ++} ++ ++/* ++ * @dir: must be locked. ++ * @dentry: target dentry. ++ */ ++int vfsub_unlink(struct inode *dir, struct path *path, ++ struct inode **delegated_inode, int force) ++{ ++ int err; ++ struct unlink_args args = { ++ .errp = &err, ++ .dir = dir, ++ .path = path, ++ .delegated_inode = delegated_inode ++ }; ++ ++ if (!force) ++ call_unlink(&args); ++ else { ++ int wkq_err; ++ ++ wkq_err = au_wkq_wait(call_unlink, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ return err; ++} +diff -Naur null/fs/aufs/vfsub.h linux-5.15.36/fs/aufs/vfsub.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/vfsub.h 2022-05-10 16:51:39.877744219 +0300 +@@ -0,0 +1,358 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * sub-routines for VFS ++ */ ++ ++#ifndef __AUFS_VFSUB_H__ ++#define __AUFS_VFSUB_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++#include "debug.h" ++ ++/* copied from linux/fs/internal.h */ ++/* todo: BAD approach!! */ ++extern void __mnt_drop_write(struct vfsmount *); ++extern struct file *alloc_empty_file(int, const struct cred *); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock subclass for lower inode */ ++/* default MAX_LOCKDEP_SUBCLASSES(8) is not enough */ ++/* reduce? gave up. */ ++enum { ++ AuLsc_I_Begin = I_MUTEX_PARENT2, /* 5 */ ++ AuLsc_I_PARENT, /* lower inode, parent first */ ++ AuLsc_I_PARENT2, /* copyup dirs */ ++ AuLsc_I_PARENT3, /* copyup wh */ ++ AuLsc_I_CHILD, ++ AuLsc_I_CHILD2, ++ AuLsc_I_End ++}; ++ ++/* to debug easier, do not make them inlined functions */ ++#define MtxMustLock(mtx) AuDebugOn(!mutex_is_locked(mtx)) ++#define IMustLock(i) AuDebugOn(!inode_is_locked(i)) ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline void vfsub_drop_nlink(struct inode *inode) ++{ ++ AuDebugOn(!inode->i_nlink); ++ drop_nlink(inode); ++} ++ ++static inline void vfsub_dead_dir(struct inode *inode) ++{ ++ AuDebugOn(!S_ISDIR(inode->i_mode)); ++ inode->i_flags |= S_DEAD; ++ clear_nlink(inode); ++} ++ ++static inline int vfsub_native_ro(struct inode *inode) ++{ ++ return sb_rdonly(inode->i_sb) ++ || IS_RDONLY(inode) ++ /* || IS_APPEND(inode) */ ++ || IS_IMMUTABLE(inode); ++} ++ ++#ifdef CONFIG_AUFS_BR_FUSE ++int vfsub_test_mntns(struct vfsmount *mnt, struct super_block *h_sb); ++#else ++AuStubInt0(vfsub_test_mntns, struct vfsmount *mnt, struct super_block *h_sb); ++#endif ++ ++int vfsub_sync_filesystem(struct super_block *h_sb); ++ ++/* ---------------------------------------------------------------------- */ ++ ++int vfsub_update_h_iattr(struct path *h_path, int *did); ++struct file *vfsub_dentry_open(struct path *path, int flags); ++struct file *vfsub_filp_open(const char *path, int oflags, int mode); ++struct au_branch; ++struct vfsub_aopen_args { ++ struct file *file; ++ unsigned int open_flag; ++ umode_t create_mode; ++ struct au_branch *br; ++}; ++int vfsub_atomic_open(struct inode *dir, struct dentry *dentry, ++ struct vfsub_aopen_args *args); ++int vfsub_kern_path(const char *name, unsigned int flags, struct path *path); ++ ++struct dentry *vfsub_lookup_one_len_unlocked(const char *name, ++ struct path *ppath, int len); ++struct dentry *vfsub_lookup_one_len(const char *name, struct path *ppath, ++ int len); ++ ++struct vfsub_lkup_one_args { ++ struct dentry **errp; ++ struct qstr *name; ++ struct path *ppath; ++}; ++ ++static inline struct dentry *vfsub_lkup_one(struct qstr *name, ++ struct path *ppath) ++{ ++ return vfsub_lookup_one_len(name->name, ppath, name->len); ++} ++ ++void vfsub_call_lkup_one(void *args); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline int vfsub_mnt_want_write(struct vfsmount *mnt) ++{ ++ int err; ++ ++ lockdep_off(); ++ err = mnt_want_write(mnt); ++ lockdep_on(); ++ return err; ++} ++ ++static inline void vfsub_mnt_drop_write(struct vfsmount *mnt) ++{ ++ lockdep_off(); ++ mnt_drop_write(mnt); ++ lockdep_on(); ++} ++ ++#if 0 /* reserved */ ++static inline void vfsub_mnt_drop_write_file(struct file *file) ++{ ++ lockdep_off(); ++ mnt_drop_write_file(file); ++ lockdep_on(); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_hinode; ++struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1, ++ struct dentry *d2, struct au_hinode *hdir2); ++void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1, ++ struct dentry *d2, struct au_hinode *hdir2); ++ ++int vfsub_create(struct inode *dir, struct path *path, int mode, ++ bool want_excl); ++int vfsub_symlink(struct inode *dir, struct path *path, ++ const char *symname); ++int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev); ++int vfsub_link(struct dentry *src_dentry, struct inode *dir, ++ struct path *path, struct inode **delegated_inode); ++int vfsub_rename(struct inode *src_hdir, struct dentry *src_dentry, ++ struct inode *hdir, struct path *path, ++ struct inode **delegated_inode, unsigned int flags); ++int vfsub_mkdir(struct inode *dir, struct path *path, int mode); ++int vfsub_rmdir(struct inode *dir, struct path *path); ++ ++/* ---------------------------------------------------------------------- */ ++ ++ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, ++ loff_t *ppos); ++ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, ++ loff_t *ppos); ++ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, ++ loff_t *ppos); ++ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, ++ loff_t *ppos); ++int vfsub_flush(struct file *file, fl_owner_t id); ++int vfsub_iterate_dir(struct file *file, struct dir_context *ctx); ++ ++static inline loff_t vfsub_f_size_read(struct file *file) ++{ ++ return i_size_read(file_inode(file)); ++} ++ ++static inline unsigned int vfsub_file_flags(struct file *file) ++{ ++ unsigned int flags; ++ ++ spin_lock(&file->f_lock); ++ flags = file->f_flags; ++ spin_unlock(&file->f_lock); ++ ++ return flags; ++} ++ ++static inline int vfsub_file_execed(struct file *file) ++{ ++ /* todo: direct access f_flags */ ++ return !!(vfsub_file_flags(file) & __FMODE_EXEC); ++} ++ ++#if 0 /* reserved */ ++static inline void vfsub_file_accessed(struct file *h_file) ++{ ++ file_accessed(h_file); ++ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL); /*ignore*/ ++} ++#endif ++ ++#if 0 /* reserved */ ++static inline void vfsub_touch_atime(struct vfsmount *h_mnt, ++ struct dentry *h_dentry) ++{ ++ struct path h_path = { ++ .dentry = h_dentry, ++ .mnt = h_mnt ++ }; ++ touch_atime(&h_path); ++ vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/ ++} ++#endif ++ ++static inline int vfsub_update_time(struct inode *h_inode, ++ struct timespec64 *ts, int flags) ++{ ++ return inode_update_time(h_inode, ts, flags); ++ /* no vfsub_update_h_iattr() since we don't have struct path */ ++} ++ ++#ifdef CONFIG_FS_POSIX_ACL ++static inline int vfsub_acl_chmod(struct user_namespace *h_userns, ++ struct inode *h_inode, umode_t h_mode) ++{ ++ int err; ++ ++ err = posix_acl_chmod(h_userns, h_inode, h_mode); ++ if (err == -EOPNOTSUPP) ++ err = 0; ++ return err; ++} ++#else ++AuStubInt0(vfsub_acl_chmod, struct user_namespace *h_userns, ++ struct inode *h_inode, umode_t h_mode); ++#endif ++ ++long vfsub_splice_to(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags); ++long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags); ++ ++static inline long vfsub_truncate(struct path *path, loff_t length) ++{ ++ long err; ++ ++ lockdep_off(); ++ err = vfs_truncate(path, length); ++ lockdep_on(); ++ return err; ++} ++ ++int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr, ++ struct file *h_file); ++int vfsub_fsync(struct file *file, struct path *path, int datasync); ++ ++/* ++ * re-use branch fs's ioctl(FICLONE) while aufs itself doesn't support such ++ * ioctl. ++ */ ++static inline loff_t vfsub_clone_file_range(struct file *src, struct file *dst, ++ loff_t len) ++{ ++ loff_t err; ++ ++ lockdep_off(); ++ err = vfs_clone_file_range(src, 0, dst, 0, len, /*remap_flags*/0); ++ lockdep_on(); ++ ++ return err; ++} ++ ++/* copy_file_range(2) is a systemcall */ ++static inline ssize_t vfsub_copy_file_range(struct file *src, loff_t src_pos, ++ struct file *dst, loff_t dst_pos, ++ size_t len, unsigned int flags) ++{ ++ ssize_t ssz; ++ ++ lockdep_off(); ++ ssz = vfs_copy_file_range(src, src_pos, dst, dst_pos, len, flags); ++ lockdep_on(); ++ ++ return ssz; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline loff_t vfsub_llseek(struct file *file, loff_t offset, int origin) ++{ ++ loff_t err; ++ ++ lockdep_off(); ++ err = vfs_llseek(file, offset, origin); ++ lockdep_on(); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode); ++int vfsub_sio_rmdir(struct inode *dir, struct path *path); ++int vfsub_sio_notify_change(struct path *path, struct iattr *ia, ++ struct inode **delegated_inode); ++int vfsub_notify_change(struct path *path, struct iattr *ia, ++ struct inode **delegated_inode); ++int vfsub_unlink(struct inode *dir, struct path *path, ++ struct inode **delegated_inode, int force); ++ ++static inline int vfsub_getattr(const struct path *path, struct kstat *st) ++{ ++ return vfs_getattr(path, st, STATX_BASIC_STATS, AT_STATX_SYNC_AS_STAT); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline int vfsub_setxattr(struct user_namespace *userns, ++ struct dentry *dentry, const char *name, ++ const void *value, size_t size, int flags) ++{ ++ int err; ++ ++ lockdep_off(); ++ err = vfs_setxattr(userns, dentry, name, value, size, flags); ++ lockdep_on(); ++ ++ return err; ++} ++ ++static inline int vfsub_removexattr(struct user_namespace *userns, ++ struct dentry *dentry, const char *name) ++{ ++ int err; ++ ++ lockdep_off(); ++ err = vfs_removexattr(userns, dentry, name); ++ lockdep_on(); ++ ++ return err; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_VFSUB_H__ */ +diff -Naur null/fs/aufs/wbr_policy.c linux-5.15.36/fs/aufs/wbr_policy.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/wbr_policy.c 2022-05-10 16:51:39.877744219 +0300 +@@ -0,0 +1,830 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * policies for selecting one among multiple writable branches ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* subset of cpup_attr() */ ++static noinline_for_stack ++int au_cpdown_attr(struct path *h_path, struct dentry *h_src) ++{ ++ int err, sbits; ++ struct iattr ia; ++ struct inode *h_isrc; ++ ++ h_isrc = d_inode(h_src); ++ ia.ia_valid = ATTR_FORCE | ATTR_MODE | ATTR_UID | ATTR_GID; ++ ia.ia_mode = h_isrc->i_mode; ++ ia.ia_uid = h_isrc->i_uid; ++ ia.ia_gid = h_isrc->i_gid; ++ sbits = !!(ia.ia_mode & (S_ISUID | S_ISGID)); ++ au_cpup_attr_flags(d_inode(h_path->dentry), h_isrc->i_flags); ++ /* no delegation since it is just created */ ++ err = vfsub_sio_notify_change(h_path, &ia, /*delegated*/NULL); ++ ++ /* is this nfs only? */ ++ if (!err && sbits && au_test_nfs(h_path->dentry->d_sb)) { ++ ia.ia_valid = ATTR_FORCE | ATTR_MODE; ++ ia.ia_mode = h_isrc->i_mode; ++ err = vfsub_sio_notify_change(h_path, &ia, /*delegated*/NULL); ++ } ++ ++ return err; ++} ++ ++#define AuCpdown_PARENT_OPQ 1 ++#define AuCpdown_WHED (1 << 1) ++#define AuCpdown_MADE_DIR (1 << 2) ++#define AuCpdown_DIROPQ (1 << 3) ++#define au_ftest_cpdown(flags, name) ((flags) & AuCpdown_##name) ++#define au_fset_cpdown(flags, name) \ ++ do { (flags) |= AuCpdown_##name; } while (0) ++#define au_fclr_cpdown(flags, name) \ ++ do { (flags) &= ~AuCpdown_##name; } while (0) ++ ++static int au_cpdown_dir_opq(struct dentry *dentry, aufs_bindex_t bdst, ++ unsigned int *flags) ++{ ++ int err; ++ struct dentry *opq_dentry; ++ ++ opq_dentry = au_diropq_create(dentry, bdst); ++ err = PTR_ERR(opq_dentry); ++ if (IS_ERR(opq_dentry)) ++ goto out; ++ dput(opq_dentry); ++ au_fset_cpdown(*flags, DIROPQ); ++ ++out: ++ return err; ++} ++ ++static int au_cpdown_dir_wh(struct dentry *dentry, struct dentry *h_parent, ++ struct inode *dir, aufs_bindex_t bdst) ++{ ++ int err; ++ struct path h_path; ++ struct au_branch *br; ++ ++ br = au_sbr(dentry->d_sb, bdst); ++ h_path.dentry = au_wh_lkup(h_parent, &dentry->d_name, br); ++ err = PTR_ERR(h_path.dentry); ++ if (IS_ERR(h_path.dentry)) ++ goto out; ++ ++ err = 0; ++ if (d_is_positive(h_path.dentry)) { ++ h_path.mnt = au_br_mnt(br); ++ err = au_wh_unlink_dentry(au_h_iptr(dir, bdst), &h_path, ++ dentry); ++ } ++ dput(h_path.dentry); ++ ++out: ++ return err; ++} ++ ++static int au_cpdown_dir(struct dentry *dentry, aufs_bindex_t bdst, ++ struct au_pin *pin, ++ struct dentry *h_parent, void *arg) ++{ ++ int err, rerr; ++ aufs_bindex_t bopq, btop; ++ struct path h_path; ++ struct dentry *parent; ++ struct inode *h_dir, *h_inode, *inode, *dir; ++ unsigned int *flags = arg; ++ ++ btop = au_dbtop(dentry); ++ /* dentry is di-locked */ ++ parent = dget_parent(dentry); ++ dir = d_inode(parent); ++ h_dir = d_inode(h_parent); ++ AuDebugOn(h_dir != au_h_iptr(dir, bdst)); ++ IMustLock(h_dir); ++ ++ err = au_lkup_neg(dentry, bdst, /*wh*/0); ++ if (unlikely(err < 0)) ++ goto out; ++ h_path.dentry = au_h_dptr(dentry, bdst); ++ h_path.mnt = au_sbr_mnt(dentry->d_sb, bdst); ++ err = vfsub_sio_mkdir(au_h_iptr(dir, bdst), &h_path, 0755); ++ if (unlikely(err)) ++ goto out_put; ++ au_fset_cpdown(*flags, MADE_DIR); ++ ++ bopq = au_dbdiropq(dentry); ++ au_fclr_cpdown(*flags, WHED); ++ au_fclr_cpdown(*flags, DIROPQ); ++ if (au_dbwh(dentry) == bdst) ++ au_fset_cpdown(*flags, WHED); ++ if (!au_ftest_cpdown(*flags, PARENT_OPQ) && bopq <= bdst) ++ au_fset_cpdown(*flags, PARENT_OPQ); ++ h_inode = d_inode(h_path.dentry); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ if (au_ftest_cpdown(*flags, WHED)) { ++ err = au_cpdown_dir_opq(dentry, bdst, flags); ++ if (unlikely(err)) { ++ inode_unlock(h_inode); ++ goto out_dir; ++ } ++ } ++ ++ err = au_cpdown_attr(&h_path, au_h_dptr(dentry, btop)); ++ inode_unlock(h_inode); ++ if (unlikely(err)) ++ goto out_opq; ++ ++ if (au_ftest_cpdown(*flags, WHED)) { ++ err = au_cpdown_dir_wh(dentry, h_parent, dir, bdst); ++ if (unlikely(err)) ++ goto out_opq; ++ } ++ ++ inode = d_inode(dentry); ++ if (au_ibbot(inode) < bdst) ++ au_set_ibbot(inode, bdst); ++ au_set_h_iptr(inode, bdst, au_igrab(h_inode), ++ au_hi_flags(inode, /*isdir*/1)); ++ au_fhsm_wrote(dentry->d_sb, bdst, /*force*/0); ++ goto out; /* success */ ++ ++ /* revert */ ++out_opq: ++ if (au_ftest_cpdown(*flags, DIROPQ)) { ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ rerr = au_diropq_remove(dentry, bdst); ++ inode_unlock(h_inode); ++ if (unlikely(rerr)) { ++ AuIOErr("failed removing diropq for %pd b%d (%d)\n", ++ dentry, bdst, rerr); ++ err = -EIO; ++ goto out; ++ } ++ } ++out_dir: ++ if (au_ftest_cpdown(*flags, MADE_DIR)) { ++ rerr = vfsub_sio_rmdir(au_h_iptr(dir, bdst), &h_path); ++ if (unlikely(rerr)) { ++ AuIOErr("failed removing %pd b%d (%d)\n", ++ dentry, bdst, rerr); ++ err = -EIO; ++ } ++ } ++out_put: ++ au_set_h_dptr(dentry, bdst, NULL); ++ if (au_dbbot(dentry) == bdst) ++ au_update_dbbot(dentry); ++out: ++ dput(parent); ++ return err; ++} ++ ++int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst) ++{ ++ int err; ++ unsigned int flags; ++ ++ flags = 0; ++ err = au_cp_dirs(dentry, bdst, au_cpdown_dir, &flags); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policies for create */ ++ ++int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ int err, i, j, ndentry; ++ aufs_bindex_t bopq; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries, *parent, *d; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ parent = dget_parent(dentry); ++ err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/0); ++ if (unlikely(err)) ++ goto out_free; ++ ++ err = bindex; ++ for (i = 0; i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ ndentry = dpage->ndentry; ++ for (j = 0; j < ndentry; j++) { ++ d = dentries[j]; ++ di_read_lock_parent2(d, !AuLock_IR); ++ bopq = au_dbdiropq(d); ++ di_read_unlock(d, !AuLock_IR); ++ if (bopq >= 0 && bopq < err) ++ err = bopq; ++ } ++ } ++ ++out_free: ++ dput(parent); ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++static int au_wbr_bu(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ for (; bindex >= 0; bindex--) ++ if (!au_br_rdonly(au_sbr(sb, bindex))) ++ return bindex; ++ return -EROFS; ++} ++ ++/* top down parent */ ++static int au_wbr_create_tdp(struct dentry *dentry, ++ unsigned int flags __maybe_unused) ++{ ++ int err; ++ aufs_bindex_t btop, bindex; ++ struct super_block *sb; ++ struct dentry *parent, *h_parent; ++ ++ sb = dentry->d_sb; ++ btop = au_dbtop(dentry); ++ err = btop; ++ if (!au_br_rdonly(au_sbr(sb, btop))) ++ goto out; ++ ++ err = -EROFS; ++ parent = dget_parent(dentry); ++ for (bindex = au_dbtop(parent); bindex < btop; bindex++) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || d_is_negative(h_parent)) ++ continue; ++ ++ if (!au_br_rdonly(au_sbr(sb, bindex))) { ++ err = bindex; ++ break; ++ } ++ } ++ dput(parent); ++ ++ /* bottom up here */ ++ if (unlikely(err < 0)) { ++ err = au_wbr_bu(sb, btop - 1); ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ } ++ ++out: ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* an exception for the policy other than tdp */ ++static int au_wbr_create_exp(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t bwh, bdiropq; ++ struct dentry *parent; ++ ++ err = -1; ++ bwh = au_dbwh(dentry); ++ parent = dget_parent(dentry); ++ bdiropq = au_dbdiropq(parent); ++ if (bwh >= 0) { ++ if (bdiropq >= 0) ++ err = min(bdiropq, bwh); ++ else ++ err = bwh; ++ AuDbg("%d\n", err); ++ } else if (bdiropq >= 0) { ++ err = bdiropq; ++ AuDbg("%d\n", err); ++ } ++ dput(parent); ++ ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ ++ if (err >= 0 && au_br_rdonly(au_sbr(dentry->d_sb, err))) ++ err = -1; ++ ++ AuDbg("%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* round robin */ ++static int au_wbr_create_init_rr(struct super_block *sb) ++{ ++ int err; ++ ++ err = au_wbr_bu(sb, au_sbbot(sb)); ++ atomic_set(&au_sbi(sb)->si_wbr_rr_next, -err); /* less important */ ++ /* smp_mb(); */ ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_create_rr(struct dentry *dentry, unsigned int flags) ++{ ++ int err, nbr; ++ unsigned int u; ++ aufs_bindex_t bindex, bbot; ++ struct super_block *sb; ++ atomic_t *next; ++ ++ err = au_wbr_create_exp(dentry); ++ if (err >= 0) ++ goto out; ++ ++ sb = dentry->d_sb; ++ next = &au_sbi(sb)->si_wbr_rr_next; ++ bbot = au_sbbot(sb); ++ nbr = bbot + 1; ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ if (!au_ftest_wbr(flags, DIR)) { ++ err = atomic_dec_return(next) + 1; ++ /* modulo for 0 is meaningless */ ++ if (unlikely(!err)) ++ err = atomic_dec_return(next) + 1; ++ } else ++ err = atomic_read(next); ++ AuDbg("%d\n", err); ++ u = err; ++ err = u % nbr; ++ AuDbg("%d\n", err); ++ if (!au_br_rdonly(au_sbr(sb, err))) ++ break; ++ err = -EROFS; ++ } ++ ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ ++out: ++ AuDbg("%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* most free space */ ++static void au_mfs(struct dentry *dentry, struct dentry *parent) ++{ ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_wbr_mfs *mfs; ++ struct dentry *h_parent; ++ aufs_bindex_t bindex, bbot; ++ int err; ++ unsigned long long b, bavail; ++ struct path h_path; ++ /* reduce the stack usage */ ++ struct kstatfs *st; ++ ++ st = kmalloc(sizeof(*st), GFP_NOFS); ++ if (unlikely(!st)) { ++ AuWarn1("failed updating mfs(%d), ignored\n", -ENOMEM); ++ return; ++ } ++ ++ bavail = 0; ++ sb = dentry->d_sb; ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ MtxMustLock(&mfs->mfs_lock); ++ mfs->mfs_bindex = -EROFS; ++ mfs->mfsrr_bytes = 0; ++ if (!parent) { ++ bindex = 0; ++ bbot = au_sbbot(sb); ++ } else { ++ bindex = au_dbtop(parent); ++ bbot = au_dbtaildir(parent); ++ } ++ ++ for (; bindex <= bbot; bindex++) { ++ if (parent) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || d_is_negative(h_parent)) ++ continue; ++ } ++ br = au_sbr(sb, bindex); ++ if (au_br_rdonly(br)) ++ continue; ++ ++ /* sb->s_root for NFS is unreliable */ ++ h_path.mnt = au_br_mnt(br); ++ h_path.dentry = h_path.mnt->mnt_root; ++ err = vfs_statfs(&h_path, st); ++ if (unlikely(err)) { ++ AuWarn1("failed statfs, b%d, %d\n", bindex, err); ++ continue; ++ } ++ ++ /* when the available size is equal, select the lower one */ ++ BUILD_BUG_ON(sizeof(b) < sizeof(st->f_bavail) ++ || sizeof(b) < sizeof(st->f_bsize)); ++ b = st->f_bavail * st->f_bsize; ++ br->br_wbr->wbr_bytes = b; ++ if (b >= bavail) { ++ bavail = b; ++ mfs->mfs_bindex = bindex; ++ mfs->mfs_jiffy = jiffies; ++ } ++ } ++ ++ mfs->mfsrr_bytes = bavail; ++ AuDbg("b%d\n", mfs->mfs_bindex); ++ au_kfree_rcu(st); ++} ++ ++static int au_wbr_create_mfs(struct dentry *dentry, unsigned int flags) ++{ ++ int err; ++ struct dentry *parent; ++ struct super_block *sb; ++ struct au_wbr_mfs *mfs; ++ ++ err = au_wbr_create_exp(dentry); ++ if (err >= 0) ++ goto out; ++ ++ sb = dentry->d_sb; ++ parent = NULL; ++ if (au_ftest_wbr(flags, PARENT)) ++ parent = dget_parent(dentry); ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ mutex_lock(&mfs->mfs_lock); ++ if (time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire) ++ || mfs->mfs_bindex < 0 ++ || au_br_rdonly(au_sbr(sb, mfs->mfs_bindex))) ++ au_mfs(dentry, parent); ++ mutex_unlock(&mfs->mfs_lock); ++ err = mfs->mfs_bindex; ++ dput(parent); ++ ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ ++out: ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_create_init_mfs(struct super_block *sb) ++{ ++ struct au_wbr_mfs *mfs; ++ ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ mutex_init(&mfs->mfs_lock); ++ mfs->mfs_jiffy = 0; ++ mfs->mfs_bindex = -EROFS; ++ ++ return 0; ++} ++ ++static int au_wbr_create_fin_mfs(struct super_block *sb __maybe_unused) ++{ ++ mutex_destroy(&au_sbi(sb)->si_wbr_mfs.mfs_lock); ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* top down regardless parent, and then mfs */ ++static int au_wbr_create_tdmfs(struct dentry *dentry, ++ unsigned int flags __maybe_unused) ++{ ++ int err; ++ aufs_bindex_t bwh, btail, bindex, bfound, bmfs; ++ unsigned long long watermark; ++ struct super_block *sb; ++ struct au_wbr_mfs *mfs; ++ struct au_branch *br; ++ struct dentry *parent; ++ ++ sb = dentry->d_sb; ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ mutex_lock(&mfs->mfs_lock); ++ if (time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire) ++ || mfs->mfs_bindex < 0) ++ au_mfs(dentry, /*parent*/NULL); ++ watermark = mfs->mfsrr_watermark; ++ bmfs = mfs->mfs_bindex; ++ mutex_unlock(&mfs->mfs_lock); ++ ++ /* another style of au_wbr_create_exp() */ ++ bwh = au_dbwh(dentry); ++ parent = dget_parent(dentry); ++ btail = au_dbtaildir(parent); ++ if (bwh >= 0 && bwh < btail) ++ btail = bwh; ++ ++ err = au_wbr_nonopq(dentry, btail); ++ if (unlikely(err < 0)) ++ goto out; ++ btail = err; ++ bfound = -1; ++ for (bindex = 0; bindex <= btail; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_rdonly(br)) ++ continue; ++ if (br->br_wbr->wbr_bytes > watermark) { ++ bfound = bindex; ++ break; ++ } ++ } ++ err = bfound; ++ if (err < 0) ++ err = bmfs; ++ ++out: ++ dput(parent); ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* most free space and then round robin */ ++static int au_wbr_create_mfsrr(struct dentry *dentry, unsigned int flags) ++{ ++ int err; ++ struct au_wbr_mfs *mfs; ++ ++ err = au_wbr_create_mfs(dentry, flags); ++ if (err >= 0) { ++ mfs = &au_sbi(dentry->d_sb)->si_wbr_mfs; ++ mutex_lock(&mfs->mfs_lock); ++ if (mfs->mfsrr_bytes < mfs->mfsrr_watermark) ++ err = au_wbr_create_rr(dentry, flags); ++ mutex_unlock(&mfs->mfs_lock); ++ } ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_create_init_mfsrr(struct super_block *sb) ++{ ++ int err; ++ ++ au_wbr_create_init_mfs(sb); /* ignore */ ++ err = au_wbr_create_init_rr(sb); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* top down parent and most free space */ ++static int au_wbr_create_pmfs(struct dentry *dentry, unsigned int flags) ++{ ++ int err, e2; ++ unsigned long long b; ++ aufs_bindex_t bindex, btop, bbot; ++ struct super_block *sb; ++ struct dentry *parent, *h_parent; ++ struct au_branch *br; ++ ++ err = au_wbr_create_tdp(dentry, flags); ++ if (unlikely(err < 0)) ++ goto out; ++ parent = dget_parent(dentry); ++ btop = au_dbtop(parent); ++ bbot = au_dbtaildir(parent); ++ if (btop == bbot) ++ goto out_parent; /* success */ ++ ++ e2 = au_wbr_create_mfs(dentry, flags); ++ if (e2 < 0) ++ goto out_parent; /* success */ ++ ++ /* when the available size is equal, select upper one */ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, err); ++ b = br->br_wbr->wbr_bytes; ++ AuDbg("b%d, %llu\n", err, b); ++ ++ for (bindex = btop; bindex <= bbot; bindex++) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || d_is_negative(h_parent)) ++ continue; ++ ++ br = au_sbr(sb, bindex); ++ if (!au_br_rdonly(br) && br->br_wbr->wbr_bytes > b) { ++ b = br->br_wbr->wbr_bytes; ++ err = bindex; ++ AuDbg("b%d, %llu\n", err, b); ++ } ++ } ++ ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ ++out_parent: ++ dput(parent); ++out: ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * - top down parent ++ * - most free space with parent ++ * - most free space round-robin regardless parent ++ */ ++static int au_wbr_create_pmfsrr(struct dentry *dentry, unsigned int flags) ++{ ++ int err; ++ unsigned long long watermark; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_wbr_mfs *mfs; ++ ++ err = au_wbr_create_pmfs(dentry, flags | AuWbr_PARENT); ++ if (unlikely(err < 0)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, err); ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ mutex_lock(&mfs->mfs_lock); ++ watermark = mfs->mfsrr_watermark; ++ mutex_unlock(&mfs->mfs_lock); ++ if (br->br_wbr->wbr_bytes < watermark) ++ /* regardless the parent dir */ ++ err = au_wbr_create_mfsrr(dentry, flags); ++ ++out: ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policies for copyup */ ++ ++/* top down parent */ ++static int au_wbr_copyup_tdp(struct dentry *dentry) ++{ ++ return au_wbr_create_tdp(dentry, /*flags, anything is ok*/0); ++} ++ ++/* bottom up parent */ ++static int au_wbr_copyup_bup(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t bindex, btop; ++ struct dentry *parent, *h_parent; ++ struct super_block *sb; ++ ++ err = -EROFS; ++ sb = dentry->d_sb; ++ parent = dget_parent(dentry); ++ btop = au_dbtop(parent); ++ for (bindex = au_dbtop(dentry); bindex >= btop; bindex--) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || d_is_negative(h_parent)) ++ continue; ++ ++ if (!au_br_rdonly(au_sbr(sb, bindex))) { ++ err = bindex; ++ break; ++ } ++ } ++ dput(parent); ++ ++ /* bottom up here */ ++ if (unlikely(err < 0)) ++ err = au_wbr_bu(sb, btop - 1); ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* bottom up */ ++int au_wbr_do_copyup_bu(struct dentry *dentry, aufs_bindex_t btop) ++{ ++ int err; ++ ++ err = au_wbr_bu(dentry->d_sb, btop); ++ AuDbg("b%d\n", err); ++ if (err > btop) ++ err = au_wbr_nonopq(dentry, err); ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_copyup_bu(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t btop; ++ ++ btop = au_dbtop(dentry); ++ err = au_wbr_do_copyup_bu(dentry, btop); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_wbr_copyup_operations au_wbr_copyup_ops[] = { ++ [AuWbrCopyup_TDP] = { ++ .copyup = au_wbr_copyup_tdp ++ }, ++ [AuWbrCopyup_BUP] = { ++ .copyup = au_wbr_copyup_bup ++ }, ++ [AuWbrCopyup_BU] = { ++ .copyup = au_wbr_copyup_bu ++ } ++}; ++ ++struct au_wbr_create_operations au_wbr_create_ops[] = { ++ [AuWbrCreate_TDP] = { ++ .create = au_wbr_create_tdp ++ }, ++ [AuWbrCreate_RR] = { ++ .create = au_wbr_create_rr, ++ .init = au_wbr_create_init_rr ++ }, ++ [AuWbrCreate_MFS] = { ++ .create = au_wbr_create_mfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_MFSV] = { ++ .create = au_wbr_create_mfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_MFSRR] = { ++ .create = au_wbr_create_mfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_MFSRRV] = { ++ .create = au_wbr_create_mfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_TDMFS] = { ++ .create = au_wbr_create_tdmfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_TDMFSV] = { ++ .create = au_wbr_create_tdmfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_PMFS] = { ++ .create = au_wbr_create_pmfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_PMFSV] = { ++ .create = au_wbr_create_pmfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_PMFSRR] = { ++ .create = au_wbr_create_pmfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_PMFSRRV] = { ++ .create = au_wbr_create_pmfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ } ++}; +diff -Naur null/fs/aufs/whout.c linux-5.15.36/fs/aufs/whout.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/whout.c 2022-05-10 16:51:39.878744219 +0300 +@@ -0,0 +1,1072 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * whiteout for logical deletion and opaque directory ++ */ ++ ++#include "aufs.h" ++ ++#define WH_MASK 0444 ++ ++/* ++ * If a directory contains this file, then it is opaque. We start with the ++ * .wh. flag so that it is blocked by lookup. ++ */ ++static struct qstr diropq_name = QSTR_INIT(AUFS_WH_DIROPQ, ++ sizeof(AUFS_WH_DIROPQ) - 1); ++ ++/* ++ * generate whiteout name, which is NOT terminated by NULL. ++ * @name: original d_name.name ++ * @len: original d_name.len ++ * @wh: whiteout qstr ++ * returns zero when succeeds, otherwise error. ++ * succeeded value as wh->name should be freed by kfree(). ++ */ ++int au_wh_name_alloc(struct qstr *wh, const struct qstr *name) ++{ ++ char *p; ++ ++ if (unlikely(name->len > PATH_MAX - AUFS_WH_PFX_LEN)) ++ return -ENAMETOOLONG; ++ ++ wh->len = name->len + AUFS_WH_PFX_LEN; ++ p = kmalloc(wh->len, GFP_NOFS); ++ wh->name = p; ++ if (p) { ++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); ++ memcpy(p + AUFS_WH_PFX_LEN, name->name, name->len); ++ /* smp_mb(); */ ++ return 0; ++ } ++ return -ENOMEM; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * test if the @wh_name exists under @h_ppath. ++ * @try_sio specifies the necessary of super-io. ++ */ ++int au_wh_test(struct user_namespace *h_userns, struct path *h_ppath, ++ struct qstr *wh_name, int try_sio) ++{ ++ int err; ++ struct dentry *wh_dentry; ++ ++ if (!try_sio) ++ wh_dentry = vfsub_lkup_one(wh_name, h_ppath); ++ else ++ wh_dentry = au_sio_lkup_one(h_userns, wh_name, h_ppath); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) { ++ if (err == -ENAMETOOLONG) ++ err = 0; ++ goto out; ++ } ++ ++ err = 0; ++ if (d_is_negative(wh_dentry)) ++ goto out_wh; /* success */ ++ ++ err = 1; ++ if (d_is_reg(wh_dentry)) ++ goto out_wh; /* success */ ++ ++ err = -EIO; ++ AuIOErr("%pd Invalid whiteout entry type 0%o.\n", ++ wh_dentry, d_inode(wh_dentry)->i_mode); ++ ++out_wh: ++ dput(wh_dentry); ++out: ++ return err; ++} ++ ++/* ++ * test if the @h_path->dentry sets opaque or not. ++ */ ++int au_diropq_test(struct user_namespace *h_userns, struct path *h_path) ++{ ++ int err; ++ struct inode *h_dir; ++ ++ h_dir = d_inode(h_path->dentry); ++ err = au_wh_test(h_userns, h_path, &diropq_name, ++ au_test_h_perm_sio(h_userns, h_dir, MAY_EXEC)); ++ return err; ++} ++ ++/* ++ * returns a negative dentry whose name is unique and temporary. ++ */ ++struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br, ++ struct qstr *prefix) ++{ ++ struct dentry *dentry; ++ int i; ++ char defname[NAME_MAX - AUFS_MAX_NAMELEN + DNAME_INLINE_LEN + 1], ++ *name, *p; ++ /* strict atomic_t is unnecessary here */ ++ static unsigned short cnt; ++ struct qstr qs; ++ struct path h_ppath; ++ struct user_namespace *h_userns; ++ ++ BUILD_BUG_ON(sizeof(cnt) * 2 > AUFS_WH_TMP_LEN); ++ ++ name = defname; ++ qs.len = sizeof(defname) - DNAME_INLINE_LEN + prefix->len - 1; ++ if (unlikely(prefix->len > DNAME_INLINE_LEN)) { ++ dentry = ERR_PTR(-ENAMETOOLONG); ++ if (unlikely(qs.len > NAME_MAX)) ++ goto out; ++ dentry = ERR_PTR(-ENOMEM); ++ name = kmalloc(qs.len + 1, GFP_NOFS); ++ if (unlikely(!name)) ++ goto out; ++ } ++ ++ /* doubly whiteout-ed */ ++ memcpy(name, AUFS_WH_PFX AUFS_WH_PFX, AUFS_WH_PFX_LEN * 2); ++ p = name + AUFS_WH_PFX_LEN * 2; ++ memcpy(p, prefix->name, prefix->len); ++ p += prefix->len; ++ *p++ = '.'; ++ AuDebugOn(name + qs.len + 1 - p <= AUFS_WH_TMP_LEN); ++ ++ h_ppath.dentry = h_parent; ++ h_ppath.mnt = au_br_mnt(br); ++ h_userns = au_br_userns(br); ++ qs.name = name; ++ for (i = 0; i < 3; i++) { ++ sprintf(p, "%.*x", AUFS_WH_TMP_LEN, cnt++); ++ dentry = au_sio_lkup_one(h_userns, &qs, &h_ppath); ++ if (IS_ERR(dentry) || d_is_negative(dentry)) ++ goto out_name; ++ dput(dentry); ++ } ++ /* pr_warn("could not get random name\n"); */ ++ dentry = ERR_PTR(-EEXIST); ++ AuDbg("%.*s\n", AuLNPair(&qs)); ++ BUG(); ++ ++out_name: ++ if (name != defname) ++ au_kfree_try_rcu(name); ++out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ++ * rename the @h_dentry on @br to the whiteouted temporary name. ++ */ ++int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br) ++{ ++ int err; ++ struct path h_path = { ++ .mnt = au_br_mnt(br) ++ }; ++ struct inode *h_dir, *delegated; ++ struct dentry *h_parent; ++ ++ h_parent = h_dentry->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ ++ h_path.dentry = au_whtmp_lkup(h_parent, br, &h_dentry->d_name); ++ err = PTR_ERR(h_path.dentry); ++ if (IS_ERR(h_path.dentry)) ++ goto out; ++ ++ /* under the same dir, no need to lock_rename() */ ++ delegated = NULL; ++ err = vfsub_rename(h_dir, h_dentry, h_dir, &h_path, &delegated, ++ /*flags*/0); ++ AuTraceErr(err); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ dput(h_path.dentry); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * functions for removing a whiteout ++ */ ++ ++static int do_unlink_wh(struct inode *h_dir, struct path *h_path) ++{ ++ int err, force; ++ struct inode *delegated; ++ ++ /* ++ * forces superio when the dir has a sticky bit. ++ * this may be a violation of unix fs semantics. ++ */ ++ force = (h_dir->i_mode & S_ISVTX) ++ && !uid_eq(current_fsuid(), d_inode(h_path->dentry)->i_uid); ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, h_path, &delegated, force); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ return err; ++} ++ ++int au_wh_unlink_dentry(struct inode *h_dir, struct path *h_path, ++ struct dentry *dentry) ++{ ++ int err; ++ ++ err = do_unlink_wh(h_dir, h_path); ++ if (!err && dentry) ++ au_set_dbwh(dentry, -1); ++ ++ return err; ++} ++ ++static int unlink_wh_name(struct path *h_ppath, struct qstr *wh) ++{ ++ int err; ++ struct path h_path; ++ ++ err = 0; ++ h_path.dentry = vfsub_lkup_one(wh, h_ppath); ++ if (IS_ERR(h_path.dentry)) ++ err = PTR_ERR(h_path.dentry); ++ else { ++ if (d_is_reg(h_path.dentry)) { ++ h_path.mnt = h_ppath->mnt; ++ err = do_unlink_wh(d_inode(h_ppath->dentry), &h_path); ++ } ++ dput(h_path.dentry); ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * initialize/clean whiteout for a branch ++ */ ++ ++static void au_wh_clean(struct inode *h_dir, struct path *whpath, ++ const int isdir) ++{ ++ int err; ++ struct inode *delegated; ++ ++ if (d_is_negative(whpath->dentry)) ++ return; ++ ++ if (isdir) ++ err = vfsub_rmdir(h_dir, whpath); ++ else { ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, whpath, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ } ++ if (unlikely(err)) ++ pr_warn("failed removing %pd (%d), ignored.\n", ++ whpath->dentry, err); ++} ++ ++static int test_linkable(struct dentry *h_root) ++{ ++ struct inode *h_dir = d_inode(h_root); ++ ++ if (h_dir->i_op->link) ++ return 0; ++ ++ pr_err("%pd (%s) doesn't support link(2), use noplink and rw+nolwh\n", ++ h_root, au_sbtype(h_root->d_sb)); ++ return -ENOSYS; /* the branch doesn't have its ->link() */ ++} ++ ++/* todo: should this mkdir be done in /sbin/mount.aufs helper? */ ++static int au_whdir(struct inode *h_dir, struct path *path) ++{ ++ int err; ++ ++ err = -EEXIST; ++ if (d_is_negative(path->dentry)) { ++ int mode = 0700; ++ ++ if (au_test_nfs(path->dentry->d_sb)) ++ mode |= 0111; ++ err = vfsub_mkdir(h_dir, path, mode); ++ } else if (d_is_dir(path->dentry)) ++ err = 0; ++ else ++ pr_err("unknown %pd exists\n", path->dentry); ++ ++ return err; ++} ++ ++struct au_wh_base { ++ const struct qstr *name; ++ struct dentry *dentry; ++}; ++ ++static void au_wh_init_ro(struct inode *h_dir, struct au_wh_base base[], ++ struct path *h_path) ++{ ++ h_path->dentry = base[AuBrWh_BASE].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/0); ++ h_path->dentry = base[AuBrWh_PLINK].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++ h_path->dentry = base[AuBrWh_ORPH].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++} ++ ++/* ++ * returns tri-state, ++ * minus: error, caller should print the message ++ * zero: success ++ * plus: error, caller should NOT print the message ++ */ ++static int au_wh_init_rw_nolink(struct dentry *h_root, struct au_wbr *wbr, ++ int do_plink, struct au_wh_base base[], ++ struct path *h_path) ++{ ++ int err; ++ struct inode *h_dir; ++ ++ h_dir = d_inode(h_root); ++ h_path->dentry = base[AuBrWh_BASE].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/0); ++ h_path->dentry = base[AuBrWh_PLINK].dentry; ++ if (do_plink) { ++ err = test_linkable(h_root); ++ if (unlikely(err)) { ++ err = 1; ++ goto out; ++ } ++ ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry); ++ } else ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++ h_path->dentry = base[AuBrWh_ORPH].dentry; ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry); ++ ++out: ++ return err; ++} ++ ++/* ++ * for the moment, aufs supports the branch filesystem which does not support ++ * link(2). testing on FAT which does not support i_op->setattr() fully either, ++ * copyup failed. finally, such filesystem will not be used as the writable ++ * branch. ++ * ++ * returns tri-state, see above. ++ */ ++static int au_wh_init_rw(struct dentry *h_root, struct au_wbr *wbr, ++ int do_plink, struct au_wh_base base[], ++ struct path *h_path) ++{ ++ int err; ++ struct inode *h_dir; ++ ++ WbrWhMustWriteLock(wbr); ++ ++ err = test_linkable(h_root); ++ if (unlikely(err)) { ++ err = 1; ++ goto out; ++ } ++ ++ /* ++ * todo: should this create be done in /sbin/mount.aufs helper? ++ */ ++ err = -EEXIST; ++ h_dir = d_inode(h_root); ++ if (d_is_negative(base[AuBrWh_BASE].dentry)) { ++ h_path->dentry = base[AuBrWh_BASE].dentry; ++ err = vfsub_create(h_dir, h_path, WH_MASK, /*want_excl*/true); ++ } else if (d_is_reg(base[AuBrWh_BASE].dentry)) ++ err = 0; ++ else ++ pr_err("unknown %pd2 exists\n", base[AuBrWh_BASE].dentry); ++ if (unlikely(err)) ++ goto out; ++ ++ h_path->dentry = base[AuBrWh_PLINK].dentry; ++ if (do_plink) { ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry); ++ } else ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++ wbr->wbr_whbase = dget(base[AuBrWh_BASE].dentry); ++ ++ h_path->dentry = base[AuBrWh_ORPH].dentry; ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry); ++ ++out: ++ return err; ++} ++ ++/* ++ * initialize the whiteout base file/dir for @br. ++ */ ++int au_wh_init(struct au_branch *br, struct super_block *sb) ++{ ++ int err, i; ++ const unsigned char do_plink ++ = !!au_opt_test(au_mntflags(sb), PLINK); ++ struct inode *h_dir; ++ struct path path = br->br_path; ++ struct dentry *h_root = path.dentry; ++ struct au_wbr *wbr = br->br_wbr; ++ static const struct qstr base_name[] = { ++ [AuBrWh_BASE] = QSTR_INIT(AUFS_BASE_NAME, ++ sizeof(AUFS_BASE_NAME) - 1), ++ [AuBrWh_PLINK] = QSTR_INIT(AUFS_PLINKDIR_NAME, ++ sizeof(AUFS_PLINKDIR_NAME) - 1), ++ [AuBrWh_ORPH] = QSTR_INIT(AUFS_ORPHDIR_NAME, ++ sizeof(AUFS_ORPHDIR_NAME) - 1) ++ }; ++ struct au_wh_base base[] = { ++ [AuBrWh_BASE] = { ++ .name = base_name + AuBrWh_BASE, ++ .dentry = NULL ++ }, ++ [AuBrWh_PLINK] = { ++ .name = base_name + AuBrWh_PLINK, ++ .dentry = NULL ++ }, ++ [AuBrWh_ORPH] = { ++ .name = base_name + AuBrWh_ORPH, ++ .dentry = NULL ++ } ++ }; ++ ++ if (wbr) ++ WbrWhMustWriteLock(wbr); ++ ++ for (i = 0; i < AuBrWh_Last; i++) { ++ /* doubly whiteouted */ ++ struct dentry *d; ++ ++ d = au_wh_lkup(h_root, (void *)base[i].name, br); ++ err = PTR_ERR(d); ++ if (IS_ERR(d)) ++ goto out; ++ ++ base[i].dentry = d; ++ AuDebugOn(wbr ++ && wbr->wbr_wh[i] ++ && wbr->wbr_wh[i] != base[i].dentry); ++ } ++ ++ if (wbr) ++ for (i = 0; i < AuBrWh_Last; i++) { ++ dput(wbr->wbr_wh[i]); ++ wbr->wbr_wh[i] = NULL; ++ } ++ ++ err = 0; ++ if (!au_br_writable(br->br_perm)) { ++ h_dir = d_inode(h_root); ++ au_wh_init_ro(h_dir, base, &path); ++ } else if (!au_br_wh_linkable(br->br_perm)) { ++ err = au_wh_init_rw_nolink(h_root, wbr, do_plink, base, &path); ++ if (err > 0) ++ goto out; ++ else if (err) ++ goto out_err; ++ } else { ++ err = au_wh_init_rw(h_root, wbr, do_plink, base, &path); ++ if (err > 0) ++ goto out; ++ else if (err) ++ goto out_err; ++ } ++ goto out; /* success */ ++ ++out_err: ++ pr_err("an error(%d) on the writable branch %pd(%s)\n", ++ err, h_root, au_sbtype(h_root->d_sb)); ++out: ++ for (i = 0; i < AuBrWh_Last; i++) ++ dput(base[i].dentry); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * whiteouts are all hard-linked usually. ++ * when its link count reaches a ceiling, we create a new whiteout base ++ * asynchronously. ++ */ ++ ++struct reinit_br_wh { ++ struct super_block *sb; ++ struct au_branch *br; ++}; ++ ++static void reinit_br_wh(void *arg) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct path h_path; ++ struct reinit_br_wh *a = arg; ++ struct au_wbr *wbr; ++ struct inode *dir, *delegated; ++ struct dentry *h_root; ++ struct au_hinode *hdir; ++ ++ err = 0; ++ wbr = a->br->br_wbr; ++ /* big aufs lock */ ++ si_noflush_write_lock(a->sb); ++ if (!au_br_writable(a->br->br_perm)) ++ goto out; ++ bindex = au_br_index(a->sb, a->br->br_id); ++ if (unlikely(bindex < 0)) ++ goto out; ++ ++ di_read_lock_parent(a->sb->s_root, AuLock_IR); ++ dir = d_inode(a->sb->s_root); ++ hdir = au_hi(dir, bindex); ++ h_root = au_h_dptr(a->sb->s_root, bindex); ++ AuDebugOn(h_root != au_br_dentry(a->br)); ++ ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ wbr_wh_write_lock(wbr); ++ err = au_h_verify(wbr->wbr_whbase, au_opt_udba(a->sb), hdir->hi_inode, ++ h_root, a->br); ++ if (!err) { ++ h_path.dentry = wbr->wbr_whbase; ++ h_path.mnt = au_br_mnt(a->br); ++ delegated = NULL; ++ err = vfsub_unlink(hdir->hi_inode, &h_path, &delegated, ++ /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ } else { ++ pr_warn("%pd is moved, ignored\n", wbr->wbr_whbase); ++ err = 0; ++ } ++ dput(wbr->wbr_whbase); ++ wbr->wbr_whbase = NULL; ++ if (!err) ++ err = au_wh_init(a->br, a->sb); ++ wbr_wh_write_unlock(wbr); ++ au_hn_inode_unlock(hdir); ++ di_read_unlock(a->sb->s_root, AuLock_IR); ++ if (!err) ++ au_fhsm_wrote(a->sb, bindex, /*force*/0); ++ ++out: ++ if (wbr) ++ atomic_dec(&wbr->wbr_wh_running); ++ au_lcnt_dec(&a->br->br_count); ++ si_write_unlock(a->sb); ++ au_nwt_done(&au_sbi(a->sb)->si_nowait); ++ au_kfree_rcu(a); ++ if (unlikely(err)) ++ AuIOErr("err %d\n", err); ++} ++ ++static void kick_reinit_br_wh(struct super_block *sb, struct au_branch *br) ++{ ++ int do_dec, wkq_err; ++ struct reinit_br_wh *arg; ++ ++ do_dec = 1; ++ if (atomic_inc_return(&br->br_wbr->wbr_wh_running) != 1) ++ goto out; ++ ++ /* ignore ENOMEM */ ++ arg = kmalloc(sizeof(*arg), GFP_NOFS); ++ if (arg) { ++ /* ++ * dec(wh_running), kfree(arg) and dec(br_count) ++ * in reinit function ++ */ ++ arg->sb = sb; ++ arg->br = br; ++ au_lcnt_inc(&br->br_count); ++ wkq_err = au_wkq_nowait(reinit_br_wh, arg, sb, /*flags*/0); ++ if (unlikely(wkq_err)) { ++ atomic_dec(&br->br_wbr->wbr_wh_running); ++ au_lcnt_dec(&br->br_count); ++ au_kfree_rcu(arg); ++ } ++ do_dec = 0; ++ } ++ ++out: ++ if (do_dec) ++ atomic_dec(&br->br_wbr->wbr_wh_running); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * create the whiteout @wh. ++ */ ++static int link_or_create_wh(struct super_block *sb, aufs_bindex_t bindex, ++ struct dentry *wh) ++{ ++ int err; ++ struct path h_path = { ++ .dentry = wh ++ }; ++ struct au_branch *br; ++ struct au_wbr *wbr; ++ struct dentry *h_parent; ++ struct inode *h_dir, *delegated; ++ ++ h_parent = wh->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ ++ br = au_sbr(sb, bindex); ++ h_path.mnt = au_br_mnt(br); ++ wbr = br->br_wbr; ++ wbr_wh_read_lock(wbr); ++ if (wbr->wbr_whbase) { ++ delegated = NULL; ++ err = vfsub_link(wbr->wbr_whbase, h_dir, &h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ if (!err || err != -EMLINK) ++ goto out; ++ ++ /* link count full. re-initialize br_whbase. */ ++ kick_reinit_br_wh(sb, br); ++ } ++ ++ /* return this error in this context */ ++ err = vfsub_create(h_dir, &h_path, WH_MASK, /*want_excl*/true); ++ if (!err) ++ au_fhsm_wrote(sb, bindex, /*force*/0); ++ ++out: ++ wbr_wh_read_unlock(wbr); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * create or remove the diropq. ++ */ ++static struct dentry *do_diropq(struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int flags) ++{ ++ struct dentry *opq_dentry; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct path h_path; ++ int err; ++ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, bindex); ++ h_path.dentry = au_h_dptr(dentry, bindex); ++ h_path.mnt = au_br_mnt(br); ++ opq_dentry = vfsub_lkup_one(&diropq_name, &h_path); ++ if (IS_ERR(opq_dentry)) ++ goto out; ++ ++ if (au_ftest_diropq(flags, CREATE)) { ++ err = link_or_create_wh(sb, bindex, opq_dentry); ++ if (!err) { ++ au_set_dbdiropq(dentry, bindex); ++ goto out; /* success */ ++ } ++ } else { ++ h_path.dentry = opq_dentry; ++ err = do_unlink_wh(au_h_iptr(d_inode(dentry), bindex), &h_path); ++ if (!err) ++ au_set_dbdiropq(dentry, -1); ++ } ++ dput(opq_dentry); ++ opq_dentry = ERR_PTR(err); ++ ++out: ++ return opq_dentry; ++} ++ ++struct do_diropq_args { ++ struct dentry **errp; ++ struct dentry *dentry; ++ aufs_bindex_t bindex; ++ unsigned int flags; ++}; ++ ++static void call_do_diropq(void *args) ++{ ++ struct do_diropq_args *a = args; ++ *a->errp = do_diropq(a->dentry, a->bindex, a->flags); ++} ++ ++struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int flags) ++{ ++ struct dentry *diropq, *h_dentry; ++ struct user_namespace *h_userns; ++ ++ h_userns = au_sbr_userns(dentry->d_sb, bindex); ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!au_test_h_perm_sio(h_userns, d_inode(h_dentry), ++ MAY_EXEC | MAY_WRITE)) ++ diropq = do_diropq(dentry, bindex, flags); ++ else { ++ int wkq_err; ++ struct do_diropq_args args = { ++ .errp = &diropq, ++ .dentry = dentry, ++ .bindex = bindex, ++ .flags = flags ++ }; ++ ++ wkq_err = au_wkq_wait(call_do_diropq, &args); ++ if (unlikely(wkq_err)) ++ diropq = ERR_PTR(wkq_err); ++ } ++ ++ return diropq; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * lookup whiteout dentry. ++ * @h_parent: lower parent dentry which must exist and be locked ++ * @base_name: name of dentry which will be whiteouted ++ * returns dentry for whiteout. ++ */ ++struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name, ++ struct au_branch *br) ++{ ++ int err; ++ struct qstr wh_name; ++ struct dentry *wh_dentry; ++ struct path h_path; ++ ++ err = au_wh_name_alloc(&wh_name, base_name); ++ wh_dentry = ERR_PTR(err); ++ if (!err) { ++ h_path.dentry = h_parent; ++ h_path.mnt = au_br_mnt(br); ++ wh_dentry = vfsub_lkup_one(&wh_name, &h_path); ++ au_kfree_try_rcu(wh_name.name); ++ } ++ return wh_dentry; ++} ++ ++/* ++ * link/create a whiteout for @dentry on @bindex. ++ */ ++struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent) ++{ ++ struct dentry *wh_dentry; ++ struct super_block *sb; ++ int err; ++ ++ sb = dentry->d_sb; ++ wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, au_sbr(sb, bindex)); ++ if (!IS_ERR(wh_dentry) && d_is_negative(wh_dentry)) { ++ err = link_or_create_wh(sb, bindex, wh_dentry); ++ if (!err) { ++ au_set_dbwh(dentry, bindex); ++ au_fhsm_wrote(sb, bindex, /*force*/0); ++ } else { ++ dput(wh_dentry); ++ wh_dentry = ERR_PTR(err); ++ } ++ } ++ ++ return wh_dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* Delete all whiteouts in this directory on branch bindex. */ ++static int del_wh_children(struct path *h_path, struct au_nhash *whlist, ++ aufs_bindex_t bindex) ++{ ++ int err; ++ unsigned long ul, n; ++ struct qstr wh_name; ++ char *p; ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ struct au_vdir_destr *str; ++ ++ err = -ENOMEM; ++ p = (void *)__get_free_page(GFP_NOFS); ++ wh_name.name = p; ++ if (unlikely(!wh_name.name)) ++ goto out; ++ ++ err = 0; ++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); ++ p += AUFS_WH_PFX_LEN; ++ n = whlist->nh_num; ++ head = whlist->nh_head; ++ for (ul = 0; !err && ul < n; ul++, head++) { ++ hlist_for_each_entry(pos, head, wh_hash) { ++ if (pos->wh_bindex != bindex) ++ continue; ++ ++ str = &pos->wh_str; ++ if (str->len + AUFS_WH_PFX_LEN <= PATH_MAX) { ++ memcpy(p, str->name, str->len); ++ wh_name.len = AUFS_WH_PFX_LEN + str->len; ++ err = unlink_wh_name(h_path, &wh_name); ++ if (!err) ++ continue; ++ break; ++ } ++ AuIOErr("whiteout name too long %.*s\n", ++ str->len, str->name); ++ err = -EIO; ++ break; ++ } ++ } ++ free_page((unsigned long)wh_name.name); ++ ++out: ++ return err; ++} ++ ++struct del_wh_children_args { ++ int *errp; ++ struct path *h_path; ++ struct au_nhash *whlist; ++ aufs_bindex_t bindex; ++}; ++ ++static void call_del_wh_children(void *args) ++{ ++ struct del_wh_children_args *a = args; ++ *a->errp = del_wh_children(a->h_path, a->whlist, a->bindex); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp) ++{ ++ struct au_whtmp_rmdir *whtmp; ++ int err; ++ unsigned int rdhash; ++ ++ SiMustAnyLock(sb); ++ ++ whtmp = kzalloc(sizeof(*whtmp), gfp); ++ if (unlikely(!whtmp)) { ++ whtmp = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ ++ /* no estimation for dir size */ ++ rdhash = au_sbi(sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = AUFS_RDHASH_DEF; ++ err = au_nhash_alloc(&whtmp->whlist, rdhash, gfp); ++ if (unlikely(err)) { ++ au_kfree_rcu(whtmp); ++ whtmp = ERR_PTR(err); ++ } ++ ++out: ++ return whtmp; ++} ++ ++void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp) ++{ ++ if (whtmp->br) ++ au_lcnt_dec(&whtmp->br->br_count); ++ dput(whtmp->wh_dentry); ++ iput(whtmp->dir); ++ au_nhash_wh_free(&whtmp->whlist); ++ au_kfree_rcu(whtmp); ++} ++ ++/* ++ * rmdir the whiteouted temporary named dir @h_dentry. ++ * @whlist: whiteouted children. ++ */ ++int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct au_nhash *whlist) ++{ ++ int err; ++ unsigned int h_nlink; ++ struct path wh_path; ++ struct inode *wh_inode, *h_dir; ++ struct au_branch *br; ++ struct user_namespace *h_userns; ++ ++ h_dir = d_inode(wh_dentry->d_parent); /* dir inode is locked */ ++ IMustLock(h_dir); ++ ++ br = au_sbr(dir->i_sb, bindex); ++ wh_path.dentry = wh_dentry; ++ wh_path.mnt = au_br_mnt(br); ++ h_userns = au_br_userns(br); ++ wh_inode = d_inode(wh_dentry); ++ inode_lock_nested(wh_inode, AuLsc_I_CHILD); ++ ++ /* ++ * someone else might change some whiteouts while we were sleeping. ++ * it means this whlist may have an obsoleted entry. ++ */ ++ if (!au_test_h_perm_sio(h_userns, wh_inode, MAY_EXEC | MAY_WRITE)) ++ err = del_wh_children(&wh_path, whlist, bindex); ++ else { ++ int wkq_err; ++ struct del_wh_children_args args = { ++ .errp = &err, ++ .h_path = &wh_path, ++ .whlist = whlist, ++ .bindex = bindex ++ }; ++ ++ wkq_err = au_wkq_wait(call_del_wh_children, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ inode_unlock(wh_inode); ++ ++ if (!err) { ++ h_nlink = h_dir->i_nlink; ++ err = vfsub_rmdir(h_dir, &wh_path); ++ /* some fs doesn't change the parent nlink in some cases */ ++ h_nlink -= h_dir->i_nlink; ++ } ++ ++ if (!err) { ++ if (au_ibtop(dir) == bindex) { ++ /* todo: dir->i_mutex is necessary */ ++ au_cpup_attr_timesizes(dir); ++ if (h_nlink) ++ vfsub_drop_nlink(dir); ++ } ++ return 0; /* success */ ++ } ++ ++ pr_warn("failed removing %pd(%d), ignored\n", wh_dentry, err); ++ return err; ++} ++ ++static void call_rmdir_whtmp(void *args) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct au_whtmp_rmdir *a = args; ++ struct super_block *sb; ++ struct dentry *h_parent; ++ struct inode *h_dir; ++ struct au_hinode *hdir; ++ ++ /* rmdir by nfsd may cause deadlock with this i_mutex */ ++ /* inode_lock(a->dir); */ ++ err = -EROFS; ++ sb = a->dir->i_sb; ++ si_read_lock(sb, !AuLock_FLUSH); ++ if (!au_br_writable(a->br->br_perm)) ++ goto out; ++ bindex = au_br_index(sb, a->br->br_id); ++ if (unlikely(bindex < 0)) ++ goto out; ++ ++ err = -EIO; ++ ii_write_lock_parent(a->dir); ++ h_parent = dget_parent(a->wh_dentry); ++ h_dir = d_inode(h_parent); ++ hdir = au_hi(a->dir, bindex); ++ err = vfsub_mnt_want_write(au_br_mnt(a->br)); ++ if (unlikely(err)) ++ goto out_mnt; ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ err = au_h_verify(a->wh_dentry, au_opt_udba(sb), h_dir, h_parent, ++ a->br); ++ if (!err) ++ err = au_whtmp_rmdir(a->dir, bindex, a->wh_dentry, &a->whlist); ++ au_hn_inode_unlock(hdir); ++ vfsub_mnt_drop_write(au_br_mnt(a->br)); ++ ++out_mnt: ++ dput(h_parent); ++ ii_write_unlock(a->dir); ++out: ++ /* inode_unlock(a->dir); */ ++ au_whtmp_rmdir_free(a); ++ si_read_unlock(sb); ++ au_nwt_done(&au_sbi(sb)->si_nowait); ++ if (unlikely(err)) ++ AuIOErr("err %d\n", err); ++} ++ ++void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct au_whtmp_rmdir *args) ++{ ++ int wkq_err; ++ struct super_block *sb; ++ ++ IMustLock(dir); ++ ++ /* all post-process will be done in do_rmdir_whtmp(). */ ++ sb = dir->i_sb; ++ args->dir = au_igrab(dir); ++ args->br = au_sbr(sb, bindex); ++ au_lcnt_inc(&args->br->br_count); ++ args->wh_dentry = dget(wh_dentry); ++ wkq_err = au_wkq_nowait(call_rmdir_whtmp, args, sb, /*flags*/0); ++ if (unlikely(wkq_err)) { ++ pr_warn("rmdir error %pd (%d), ignored\n", wh_dentry, wkq_err); ++ au_whtmp_rmdir_free(args); ++ } ++} +diff -Naur null/fs/aufs/whout.h linux-5.15.36/fs/aufs/whout.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/whout.h 2022-05-10 16:51:39.878744219 +0300 +@@ -0,0 +1,87 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * whiteout for logical deletion and opaque directory ++ */ ++ ++#ifndef __AUFS_WHOUT_H__ ++#define __AUFS_WHOUT_H__ ++ ++#ifdef __KERNEL__ ++ ++#include "dir.h" ++ ++/* whout.c */ ++int au_wh_name_alloc(struct qstr *wh, const struct qstr *name); ++int au_wh_test(struct user_namespace *h_userns, struct path *h_ppath, ++ struct qstr *wh_name, int try_sio); ++int au_diropq_test(struct user_namespace *h_userns, struct path *h_path); ++struct au_branch; ++struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br, ++ struct qstr *prefix); ++int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br); ++int au_wh_unlink_dentry(struct inode *h_dir, struct path *h_path, ++ struct dentry *dentry); ++int au_wh_init(struct au_branch *br, struct super_block *sb); ++ ++/* diropq flags */ ++#define AuDiropq_CREATE 1 ++#define au_ftest_diropq(flags, name) ((flags) & AuDiropq_##name) ++#define au_fset_diropq(flags, name) \ ++ do { (flags) |= AuDiropq_##name; } while (0) ++#define au_fclr_diropq(flags, name) \ ++ do { (flags) &= ~AuDiropq_##name; } while (0) ++ ++struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int flags); ++struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name, ++ struct au_branch *br); ++struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent); ++ ++/* real rmdir for the whiteout-ed dir */ ++struct au_whtmp_rmdir { ++ struct inode *dir; ++ struct au_branch *br; ++ struct dentry *wh_dentry; ++ struct au_nhash whlist; ++}; ++ ++struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp); ++void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp); ++int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct au_nhash *whlist); ++void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct au_whtmp_rmdir *args); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct dentry *au_diropq_create(struct dentry *dentry, ++ aufs_bindex_t bindex) ++{ ++ return au_diropq_sio(dentry, bindex, AuDiropq_CREATE); ++} ++ ++static inline int au_diropq_remove(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ return PTR_ERR(au_diropq_sio(dentry, bindex, !AuDiropq_CREATE)); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_WHOUT_H__ */ +diff -Naur null/fs/aufs/wkq.c linux-5.15.36/fs/aufs/wkq.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/wkq.c 2022-05-10 16:51:39.878744219 +0300 +@@ -0,0 +1,372 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * workqueue for asynchronous/super-io operations ++ * todo: try new credential scheme ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* internal workqueue named AUFS_WKQ_NAME */ ++ ++static struct workqueue_struct *au_wkq; ++ ++struct au_wkinfo { ++ struct work_struct wk; ++ struct kobject *kobj; ++ ++ unsigned int flags; /* see wkq.h */ ++ ++ au_wkq_func_t func; ++ void *args; ++ ++#ifdef CONFIG_LOCKDEP ++ int dont_check; ++ struct held_lock **hlock; ++#endif ++ ++ struct completion *comp; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * Aufs passes some operations to the workqueue such as the internal copyup. ++ * This scheme looks rather unnatural for LOCKDEP debugging feature, since the ++ * job run by workqueue depends upon the locks acquired in the other task. ++ * Delegating a small operation to the workqueue, aufs passes its lockdep ++ * information too. And the job in the workqueue restores the info in order to ++ * pretend as if it acquired those locks. This is just to make LOCKDEP work ++ * correctly and expectedly. ++ */ ++ ++#ifndef CONFIG_LOCKDEP ++AuStubInt0(au_wkq_lockdep_alloc, struct au_wkinfo *wkinfo); ++AuStubVoid(au_wkq_lockdep_free, struct au_wkinfo *wkinfo); ++AuStubVoid(au_wkq_lockdep_pre, struct au_wkinfo *wkinfo); ++AuStubVoid(au_wkq_lockdep_post, struct au_wkinfo *wkinfo); ++AuStubVoid(au_wkq_lockdep_init, struct au_wkinfo *wkinfo); ++#else ++static void au_wkq_lockdep_init(struct au_wkinfo *wkinfo) ++{ ++ wkinfo->hlock = NULL; ++ wkinfo->dont_check = 0; ++} ++ ++/* ++ * 1: matched ++ * 0: unmatched ++ */ ++static int au_wkq_lockdep_test(struct lock_class_key *key, const char *name) ++{ ++ static DEFINE_SPINLOCK(spin); ++ static struct { ++ char *name; ++ struct lock_class_key *key; ++ } a[] = { ++ { .name = "&sbinfo->si_rwsem" }, ++ { .name = "&finfo->fi_rwsem" }, ++ { .name = "&dinfo->di_rwsem" }, ++ { .name = "&iinfo->ii_rwsem" } ++ }; ++ static int set; ++ int i; ++ ++ /* lockless read from 'set.' see below */ ++ if (set == ARRAY_SIZE(a)) { ++ for (i = 0; i < ARRAY_SIZE(a); i++) ++ if (a[i].key == key) ++ goto match; ++ goto unmatch; ++ } ++ ++ spin_lock(&spin); ++ if (set) ++ for (i = 0; i < ARRAY_SIZE(a); i++) ++ if (a[i].key == key) { ++ spin_unlock(&spin); ++ goto match; ++ } ++ for (i = 0; i < ARRAY_SIZE(a); i++) { ++ if (a[i].key) { ++ if (unlikely(a[i].key == key)) { /* rare but possible */ ++ spin_unlock(&spin); ++ goto match; ++ } else ++ continue; ++ } ++ if (strstr(a[i].name, name)) { ++ /* ++ * the order of these three lines is important for the ++ * lockless read above. ++ */ ++ a[i].key = key; ++ spin_unlock(&spin); ++ set++; ++ /* AuDbg("%d, %s\n", set, name); */ ++ goto match; ++ } ++ } ++ spin_unlock(&spin); ++ goto unmatch; ++ ++match: ++ return 1; ++unmatch: ++ return 0; ++} ++ ++static int au_wkq_lockdep_alloc(struct au_wkinfo *wkinfo) ++{ ++ int err, n; ++ struct task_struct *curr; ++ struct held_lock **hl, *held_locks, *p; ++ ++ err = 0; ++ curr = current; ++ wkinfo->dont_check = lockdep_recursing(curr); ++ if (wkinfo->dont_check) ++ goto out; ++ n = curr->lockdep_depth; ++ if (!n) ++ goto out; ++ ++ err = -ENOMEM; ++ wkinfo->hlock = kmalloc_array(n + 1, sizeof(*wkinfo->hlock), GFP_NOFS); ++ if (unlikely(!wkinfo->hlock)) ++ goto out; ++ ++ err = 0; ++#if 0 /* left for debugging */ ++ if (0 && au_debug_test()) ++ lockdep_print_held_locks(curr); ++#endif ++ held_locks = curr->held_locks; ++ hl = wkinfo->hlock; ++ while (n--) { ++ p = held_locks++; ++ if (au_wkq_lockdep_test(p->instance->key, p->instance->name)) ++ *hl++ = p; ++ } ++ *hl = NULL; ++ ++out: ++ return err; ++} ++ ++static void au_wkq_lockdep_free(struct au_wkinfo *wkinfo) ++{ ++ au_kfree_try_rcu(wkinfo->hlock); ++} ++ ++static void au_wkq_lockdep_pre(struct au_wkinfo *wkinfo) ++{ ++ struct held_lock *p, **hl = wkinfo->hlock; ++ int subclass; ++ ++ if (wkinfo->dont_check) ++ lockdep_off(); ++ if (!hl) ++ return; ++ while ((p = *hl++)) { /* assignment */ ++ subclass = lockdep_hlock_class(p)->subclass; ++ /* AuDbg("%s, %d\n", p->instance->name, subclass); */ ++ if (p->read) ++ rwsem_acquire_read(p->instance, subclass, 0, ++ /*p->acquire_ip*/_RET_IP_); ++ else ++ rwsem_acquire(p->instance, subclass, 0, ++ /*p->acquire_ip*/_RET_IP_); ++ } ++} ++ ++static void au_wkq_lockdep_post(struct au_wkinfo *wkinfo) ++{ ++ struct held_lock *p, **hl = wkinfo->hlock; ++ ++ if (wkinfo->dont_check) ++ lockdep_on(); ++ if (!hl) ++ return; ++ while ((p = *hl++)) /* assignment */ ++ rwsem_release(p->instance, /*p->acquire_ip*/_RET_IP_); ++} ++#endif ++ ++static void wkq_func(struct work_struct *wk) ++{ ++ struct au_wkinfo *wkinfo = container_of(wk, struct au_wkinfo, wk); ++ ++ AuDebugOn(!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)); ++ AuDebugOn(rlimit(RLIMIT_FSIZE) != RLIM_INFINITY); ++ ++ au_wkq_lockdep_pre(wkinfo); ++ wkinfo->func(wkinfo->args); ++ au_wkq_lockdep_post(wkinfo); ++ if (au_ftest_wkq(wkinfo->flags, WAIT)) ++ complete(wkinfo->comp); ++ else { ++ kobject_put(wkinfo->kobj); ++ module_put(THIS_MODULE); /* todo: ?? */ ++ au_kfree_rcu(wkinfo); ++ } ++} ++ ++/* ++ * Since struct completion is large, try allocating it dynamically. ++ */ ++#define AuWkqCompDeclare(name) struct completion *comp = NULL ++ ++static int au_wkq_comp_alloc(struct au_wkinfo *wkinfo, struct completion **comp) ++{ ++ *comp = kmalloc(sizeof(**comp), GFP_NOFS); ++ if (*comp) { ++ init_completion(*comp); ++ wkinfo->comp = *comp; ++ return 0; ++ } ++ return -ENOMEM; ++} ++ ++static void au_wkq_comp_free(struct completion *comp) ++{ ++ au_kfree_rcu(comp); ++} ++ ++static void au_wkq_run(struct au_wkinfo *wkinfo) ++{ ++ if (au_ftest_wkq(wkinfo->flags, NEST)) { ++ if (au_wkq_test()) { ++ AuWarn1("wkq from wkq, unless silly-rename on NFS," ++ " due to a dead dir by UDBA," ++ " or async xino write?\n"); ++ AuDebugOn(au_ftest_wkq(wkinfo->flags, WAIT)); ++ } ++ } else ++ au_dbg_verify_kthread(); ++ ++ if (au_ftest_wkq(wkinfo->flags, WAIT)) { ++ INIT_WORK_ONSTACK(&wkinfo->wk, wkq_func); ++ queue_work(au_wkq, &wkinfo->wk); ++ } else { ++ INIT_WORK(&wkinfo->wk, wkq_func); ++ schedule_work(&wkinfo->wk); ++ } ++} ++ ++/* ++ * Be careful. It is easy to make deadlock happen. ++ * processA: lock, wkq and wait ++ * processB: wkq and wait, lock in wkq ++ * --> deadlock ++ */ ++int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args) ++{ ++ int err; ++ AuWkqCompDeclare(comp); ++ struct au_wkinfo wkinfo = { ++ .flags = flags, ++ .func = func, ++ .args = args ++ }; ++ ++ err = au_wkq_comp_alloc(&wkinfo, &comp); ++ if (unlikely(err)) ++ goto out; ++ err = au_wkq_lockdep_alloc(&wkinfo); ++ if (unlikely(err)) ++ goto out_comp; ++ if (!err) { ++ au_wkq_run(&wkinfo); ++ /* no timeout, no interrupt */ ++ wait_for_completion(wkinfo.comp); ++ } ++ au_wkq_lockdep_free(&wkinfo); ++ ++out_comp: ++ au_wkq_comp_free(comp); ++out: ++ destroy_work_on_stack(&wkinfo.wk); ++ return err; ++} ++ ++/* ++ * Note: dget/dput() in func for aufs dentries are not supported. It will be a ++ * problem in a concurrent umounting. ++ */ ++int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb, ++ unsigned int flags) ++{ ++ int err; ++ struct au_wkinfo *wkinfo; ++ ++ atomic_inc(&au_sbi(sb)->si_nowait.nw_len); ++ ++ /* ++ * wkq_func() must free this wkinfo. ++ * it highly depends upon the implementation of workqueue. ++ */ ++ err = 0; ++ wkinfo = kmalloc(sizeof(*wkinfo), GFP_NOFS); ++ if (wkinfo) { ++ wkinfo->kobj = &au_sbi(sb)->si_kobj; ++ wkinfo->flags = flags & ~AuWkq_WAIT; ++ wkinfo->func = func; ++ wkinfo->args = args; ++ wkinfo->comp = NULL; ++ au_wkq_lockdep_init(wkinfo); ++ kobject_get(wkinfo->kobj); ++ __module_get(THIS_MODULE); /* todo: ?? */ ++ ++ au_wkq_run(wkinfo); ++ } else { ++ err = -ENOMEM; ++ au_nwt_done(&au_sbi(sb)->si_nowait); ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_nwt_init(struct au_nowait_tasks *nwt) ++{ ++ atomic_set(&nwt->nw_len, 0); ++ /* smp_mb(); */ /* atomic_set */ ++ init_waitqueue_head(&nwt->nw_wq); ++} ++ ++void au_wkq_fin(void) ++{ ++ destroy_workqueue(au_wkq); ++} ++ ++int __init au_wkq_init(void) ++{ ++ int err; ++ ++ err = 0; ++ au_wkq = alloc_workqueue(AUFS_WKQ_NAME, 0, WQ_DFL_ACTIVE); ++ if (IS_ERR(au_wkq)) ++ err = PTR_ERR(au_wkq); ++ else if (!au_wkq) ++ err = -ENOMEM; ++ ++ return err; ++} +diff -Naur null/fs/aufs/wkq.h linux-5.15.36/fs/aufs/wkq.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/wkq.h 2022-05-10 16:51:39.878744219 +0300 +@@ -0,0 +1,89 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * workqueue for asynchronous/super-io operations ++ * todo: try new credentials management scheme ++ */ ++ ++#ifndef __AUFS_WKQ_H__ ++#define __AUFS_WKQ_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++struct super_block; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * in the next operation, wait for the 'nowait' tasks in system-wide workqueue ++ */ ++struct au_nowait_tasks { ++ atomic_t nw_len; ++ wait_queue_head_t nw_wq; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++typedef void (*au_wkq_func_t)(void *args); ++ ++/* wkq flags */ ++#define AuWkq_WAIT 1 ++#define AuWkq_NEST (1 << 1) ++#define au_ftest_wkq(flags, name) ((flags) & AuWkq_##name) ++#define au_fset_wkq(flags, name) \ ++ do { (flags) |= AuWkq_##name; } while (0) ++#define au_fclr_wkq(flags, name) \ ++ do { (flags) &= ~AuWkq_##name; } while (0) ++ ++/* wkq.c */ ++int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args); ++int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb, ++ unsigned int flags); ++void au_nwt_init(struct au_nowait_tasks *nwt); ++int __init au_wkq_init(void); ++void au_wkq_fin(void); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline int au_wkq_test(void) ++{ ++ return current->flags & PF_WQ_WORKER; ++} ++ ++static inline int au_wkq_wait(au_wkq_func_t func, void *args) ++{ ++ return au_wkq_do_wait(AuWkq_WAIT, func, args); ++} ++ ++static inline void au_nwt_done(struct au_nowait_tasks *nwt) ++{ ++ if (atomic_dec_and_test(&nwt->nw_len)) ++ wake_up_all(&nwt->nw_wq); ++} ++ ++static inline int au_nwt_flush(struct au_nowait_tasks *nwt) ++{ ++ wait_event(nwt->nw_wq, !atomic_read(&nwt->nw_len)); ++ return 0; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_WKQ_H__ */ +diff -Naur null/fs/aufs/xattr.c linux-5.15.36/fs/aufs/xattr.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/xattr.c 2022-05-10 16:51:39.878744219 +0300 +@@ -0,0 +1,368 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2014-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * handling xattr functions ++ */ ++ ++#include ++#include ++#include ++#include "aufs.h" ++ ++static int au_xattr_ignore(int err, char *name, unsigned int ignore_flags) ++{ ++ if (!ignore_flags) ++ goto out; ++ switch (err) { ++ case -ENOMEM: ++ case -EDQUOT: ++ goto out; ++ } ++ ++ if ((ignore_flags & AuBrAttr_ICEX) == AuBrAttr_ICEX) { ++ err = 0; ++ goto out; ++ } ++ ++#define cmp(brattr, prefix) do { \ ++ if (!strncmp(name, XATTR_##prefix##_PREFIX, \ ++ XATTR_##prefix##_PREFIX_LEN)) { \ ++ if (ignore_flags & AuBrAttr_ICEX_##brattr) \ ++ err = 0; \ ++ goto out; \ ++ } \ ++ } while (0) ++ ++ cmp(SEC, SECURITY); ++ cmp(SYS, SYSTEM); ++ cmp(TR, TRUSTED); ++ cmp(USR, USER); ++#undef cmp ++ ++ if (ignore_flags & AuBrAttr_ICEX_OTH) ++ err = 0; ++ ++out: ++ return err; ++} ++ ++static const int au_xattr_out_of_list = AuBrAttr_ICEX_OTH << 1; ++ ++static int au_do_cpup_xattr(struct path *h_dst, struct path *h_src, ++ char *name, char **buf, unsigned int ignore_flags, ++ unsigned int verbose) ++{ ++ int err; ++ ssize_t ssz; ++ struct inode *h_idst; ++ struct dentry *h_dst_dentry, *h_src_dentry; ++ struct user_namespace *h_dst_userns, *h_src_userns; ++ ++ h_src_userns = mnt_user_ns(h_src->mnt); ++ h_src_dentry = h_src->dentry; ++ ssz = vfs_getxattr_alloc(h_src_userns, h_src_dentry, name, buf, 0, ++ GFP_NOFS); ++ err = ssz; ++ if (unlikely(err <= 0)) { ++ if (err == -ENODATA ++ || (err == -EOPNOTSUPP ++ && ((ignore_flags & au_xattr_out_of_list) ++ || (au_test_nfs_noacl(d_inode(h_src_dentry)) ++ && (!strcmp(name, XATTR_NAME_POSIX_ACL_ACCESS) ++ || !strcmp(name, ++ XATTR_NAME_POSIX_ACL_DEFAULT)))) ++ )) ++ err = 0; ++ if (err && (verbose || au_debug_test())) ++ pr_err("%s, err %d\n", name, err); ++ goto out; ++ } ++ ++ /* unlock it temporary */ ++ h_dst_userns = mnt_user_ns(h_dst->mnt); ++ h_dst_dentry = h_dst->dentry; ++ h_idst = d_inode(h_dst_dentry); ++ inode_unlock(h_idst); ++ err = vfsub_setxattr(h_dst_userns, h_dst_dentry, name, *buf, ssz, ++ /*flags*/0); ++ inode_lock_nested(h_idst, AuLsc_I_CHILD2); ++ if (unlikely(err)) { ++ if (verbose || au_debug_test()) ++ pr_err("%s, err %d\n", name, err); ++ err = au_xattr_ignore(err, name, ignore_flags); ++ } ++ ++out: ++ return err; ++} ++ ++int au_cpup_xattr(struct path *h_dst, struct path *h_src, int ignore_flags, ++ unsigned int verbose) ++{ ++ int err, unlocked, acl_access, acl_default; ++ ssize_t ssz; ++ struct dentry *h_dst_dentry, *h_src_dentry; ++ struct inode *h_isrc, *h_idst; ++ char *value, *p, *o, *e; ++ ++ /* try stopping to update the source inode while we are referencing */ ++ /* there should not be the parent-child relationship between them */ ++ h_dst_dentry = h_dst->dentry; ++ h_idst = d_inode(h_dst_dentry); ++ h_src_dentry = h_src->dentry; ++ h_isrc = d_inode(h_src_dentry); ++ inode_unlock(h_idst); ++ inode_lock_shared_nested(h_isrc, AuLsc_I_CHILD); ++ inode_lock_nested(h_idst, AuLsc_I_CHILD2); ++ unlocked = 0; ++ ++ /* some filesystems don't list POSIX ACL, for example tmpfs */ ++ ssz = vfs_listxattr(h_src_dentry, NULL, 0); ++ err = ssz; ++ if (unlikely(err < 0)) { ++ AuTraceErr(err); ++ if (err == -ENODATA ++ || err == -EOPNOTSUPP) ++ err = 0; /* ignore */ ++ goto out; ++ } ++ ++ err = 0; ++ p = NULL; ++ o = NULL; ++ if (ssz) { ++ err = -ENOMEM; ++ p = kmalloc(ssz, GFP_NOFS); ++ o = p; ++ if (unlikely(!p)) ++ goto out; ++ err = vfs_listxattr(h_src_dentry, p, ssz); ++ } ++ inode_unlock_shared(h_isrc); ++ unlocked = 1; ++ AuDbg("err %d, ssz %zd\n", err, ssz); ++ if (unlikely(err < 0)) ++ goto out_free; ++ ++ err = 0; ++ e = p + ssz; ++ value = NULL; ++ acl_access = 0; ++ acl_default = 0; ++ while (!err && p < e) { ++ acl_access |= !strncmp(p, XATTR_NAME_POSIX_ACL_ACCESS, ++ sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1); ++ acl_default |= !strncmp(p, XATTR_NAME_POSIX_ACL_DEFAULT, ++ sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) ++ - 1); ++ err = au_do_cpup_xattr(h_dst, h_src, p, &value, ignore_flags, ++ verbose); ++ p += strlen(p) + 1; ++ } ++ AuTraceErr(err); ++ ignore_flags |= au_xattr_out_of_list; ++ if (!err && !acl_access) { ++ err = au_do_cpup_xattr(h_dst, h_src, ++ XATTR_NAME_POSIX_ACL_ACCESS, &value, ++ ignore_flags, verbose); ++ AuTraceErr(err); ++ } ++ if (!err && !acl_default) { ++ err = au_do_cpup_xattr(h_dst, h_src, ++ XATTR_NAME_POSIX_ACL_DEFAULT, &value, ++ ignore_flags, verbose); ++ AuTraceErr(err); ++ } ++ ++ au_kfree_try_rcu(value); ++ ++out_free: ++ au_kfree_try_rcu(o); ++out: ++ if (!unlocked) ++ inode_unlock_shared(h_isrc); ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_smack_reentering(struct super_block *sb) ++{ ++#if IS_ENABLED(CONFIG_SECURITY_SMACK) || IS_ENABLED(CONFIG_SECURITY_SELINUX) ++ /* ++ * as a part of lookup, smack_d_instantiate() is called, and it calls ++ * i_op->getxattr(). ouch. ++ */ ++ return si_pid_test(sb); ++#else ++ return 0; ++#endif ++} ++ ++enum { ++ AU_XATTR_LIST, ++ AU_XATTR_GET ++}; ++ ++struct au_lgxattr { ++ int type; ++ union { ++ struct { ++ char *list; ++ size_t size; ++ } list; ++ struct { ++ const char *name; ++ void *value; ++ size_t size; ++ } get; ++ } u; ++}; ++ ++static ssize_t au_lgxattr(struct dentry *dentry, struct inode *inode, ++ struct au_lgxattr *arg) ++{ ++ ssize_t err; ++ int reenter; ++ struct path h_path; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ reenter = au_smack_reentering(sb); ++ if (!reenter) { ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out; ++ } ++ err = au_h_path_getattr(dentry, inode, /*force*/1, &h_path, reenter); ++ if (unlikely(err)) ++ goto out_si; ++ if (unlikely(!h_path.dentry)) ++ /* illegally overlapped or something */ ++ goto out_di; /* pretending success */ ++ ++ /* always topmost entry only */ ++ switch (arg->type) { ++ case AU_XATTR_LIST: ++ err = vfs_listxattr(h_path.dentry, ++ arg->u.list.list, arg->u.list.size); ++ break; ++ case AU_XATTR_GET: ++ AuDebugOn(d_is_negative(h_path.dentry)); ++ err = vfs_getxattr(mnt_user_ns(h_path.mnt), h_path.dentry, ++ arg->u.get.name, arg->u.get.value, ++ arg->u.get.size); ++ break; ++ } ++ ++out_di: ++ if (!reenter) ++ di_read_unlock(dentry, AuLock_IR); ++out_si: ++ if (!reenter) ++ si_read_unlock(sb); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++ssize_t aufs_listxattr(struct dentry *dentry, char *list, size_t size) ++{ ++ struct au_lgxattr arg = { ++ .type = AU_XATTR_LIST, ++ .u.list = { ++ .list = list, ++ .size = size ++ }, ++ }; ++ ++ return au_lgxattr(dentry, /*inode*/NULL, &arg); ++} ++ ++static ssize_t au_getxattr(struct dentry *dentry, struct inode *inode, ++ const char *name, void *value, size_t size) ++{ ++ struct au_lgxattr arg = { ++ .type = AU_XATTR_GET, ++ .u.get = { ++ .name = name, ++ .value = value, ++ .size = size ++ }, ++ }; ++ ++ return au_lgxattr(dentry, inode, &arg); ++} ++ ++static int au_setxattr(struct dentry *dentry, struct inode *inode, ++ const char *name, const void *value, size_t size, ++ int flags) ++{ ++ struct au_sxattr arg = { ++ .type = AU_XATTR_SET, ++ .u.set = { ++ .name = name, ++ .value = value, ++ .size = size, ++ .flags = flags ++ }, ++ }; ++ ++ return au_sxattr(dentry, inode, &arg); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_xattr_get(const struct xattr_handler *handler, ++ struct dentry *dentry, struct inode *inode, ++ const char *name, void *buffer, size_t size) ++{ ++ return au_getxattr(dentry, inode, name, buffer, size); ++} ++ ++static int au_xattr_set(const struct xattr_handler *handler, ++ struct user_namespace *userns, ++ struct dentry *dentry, struct inode *inode, ++ const char *name, const void *value, size_t size, ++ int flags) ++{ ++ return au_setxattr(dentry, inode, name, value, size, flags); ++} ++ ++static const struct xattr_handler au_xattr_handler = { ++ .name = "", ++ .prefix = "", ++ .get = au_xattr_get, ++ .set = au_xattr_set ++}; ++ ++static const struct xattr_handler *au_xattr_handlers[] = { ++#ifdef CONFIG_FS_POSIX_ACL ++ &posix_acl_access_xattr_handler, ++ &posix_acl_default_xattr_handler, ++#endif ++ &au_xattr_handler, /* must be last */ ++ NULL ++}; ++ ++void au_xattr_init(struct super_block *sb) ++{ ++ sb->s_xattr = au_xattr_handlers; ++} +diff -Naur null/fs/aufs/xino.c linux-5.15.36/fs/aufs/xino.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/xino.c 2022-05-10 16:51:39.879744219 +0300 +@@ -0,0 +1,1926 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * external inode number translation table and bitmap ++ * ++ * things to consider ++ * - the lifetime ++ * + au_xino object ++ * + XINO files (xino, xib, xigen) ++ * + dynamic debugfs entries (xiN) ++ * + static debugfs entries (xib, xigen) ++ * + static sysfs entry (xi_path) ++ * - several entry points to handle them. ++ * + mount(2) without xino option (default) ++ * + mount(2) with xino option ++ * + mount(2) with noxino option ++ * + umount(2) ++ * + remount with add/del branches ++ * + remount with xino/noxino options ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++static aufs_bindex_t sbr_find_shared(struct super_block *sb, aufs_bindex_t btop, ++ aufs_bindex_t bbot, ++ struct super_block *h_sb) ++{ ++ /* todo: try binary-search if the branches are many */ ++ for (; btop <= bbot; btop++) ++ if (h_sb == au_sbr_sb(sb, btop)) ++ return btop; ++ return -1; ++} ++ ++/* ++ * find another branch who is on the same filesystem of the specified ++ * branch{@btgt}. search until @bbot. ++ */ ++static aufs_bindex_t is_sb_shared(struct super_block *sb, aufs_bindex_t btgt, ++ aufs_bindex_t bbot) ++{ ++ aufs_bindex_t bindex; ++ struct super_block *tgt_sb; ++ ++ tgt_sb = au_sbr_sb(sb, btgt); ++ bindex = sbr_find_shared(sb, /*btop*/0, btgt - 1, tgt_sb); ++ if (bindex < 0) ++ bindex = sbr_find_shared(sb, btgt + 1, bbot, tgt_sb); ++ ++ return bindex; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * stop unnecessary notify events at creating xino files ++ */ ++ ++aufs_bindex_t au_xi_root(struct super_block *sb, struct dentry *dentry) ++{ ++ aufs_bindex_t bfound, bindex, bbot; ++ struct dentry *parent; ++ struct au_branch *br; ++ ++ bfound = -1; ++ parent = dentry->d_parent; /* safe d_parent access */ ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_dentry(br) == parent) { ++ bfound = bindex; ++ break; ++ } ++ } ++ ++ AuDbg("bfound b%d\n", bfound); ++ return bfound; ++} ++ ++struct au_xino_lock_dir { ++ struct au_hinode *hdir; ++ struct dentry *parent; ++ struct inode *dir; ++}; ++ ++static struct dentry *au_dget_parent_lock(struct dentry *dentry, ++ unsigned int lsc) ++{ ++ struct dentry *parent; ++ struct inode *dir; ++ ++ parent = dget_parent(dentry); ++ dir = d_inode(parent); ++ inode_lock_nested(dir, lsc); ++#if 0 /* it should not happen */ ++ spin_lock(&dentry->d_lock); ++ if (unlikely(dentry->d_parent != parent)) { ++ spin_unlock(&dentry->d_lock); ++ inode_unlock(dir); ++ dput(parent); ++ parent = NULL; ++ goto out; ++ } ++ spin_unlock(&dentry->d_lock); ++ ++out: ++#endif ++ return parent; ++} ++ ++static void au_xino_lock_dir(struct super_block *sb, struct path *xipath, ++ struct au_xino_lock_dir *ldir) ++{ ++ aufs_bindex_t bindex; ++ ++ ldir->hdir = NULL; ++ bindex = au_xi_root(sb, xipath->dentry); ++ if (bindex >= 0) { ++ /* rw branch root */ ++ ldir->hdir = au_hi(d_inode(sb->s_root), bindex); ++ au_hn_inode_lock_nested(ldir->hdir, AuLsc_I_PARENT); ++ } else { ++ /* other */ ++ ldir->parent = au_dget_parent_lock(xipath->dentry, ++ AuLsc_I_PARENT); ++ ldir->dir = d_inode(ldir->parent); ++ } ++} ++ ++static void au_xino_unlock_dir(struct au_xino_lock_dir *ldir) ++{ ++ if (ldir->hdir) ++ au_hn_inode_unlock(ldir->hdir); ++ else { ++ inode_unlock(ldir->dir); ++ dput(ldir->parent); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * create and set a new xino file ++ */ ++struct file *au_xino_create(struct super_block *sb, char *fpath, int silent, ++ int wbrtop) ++{ ++ struct file *file; ++ struct dentry *h_parent, *d; ++ struct inode *h_dir, *inode; ++ int err; ++ static DEFINE_MUTEX(mtx); ++ ++ /* ++ * at mount-time, and the xino file is the default path, ++ * hnotify is disabled so we have no notify events to ignore. ++ * when a user specified the xino, we cannot get au_hdir to be ignored. ++ */ ++ if (!wbrtop) ++ mutex_lock(&mtx); ++ file = vfsub_filp_open(fpath, O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE ++ /* | __FMODE_NONOTIFY */, ++ 0666); ++ if (IS_ERR(file)) { ++ if (!wbrtop) ++ mutex_unlock(&mtx); ++ if (!silent) ++ pr_err("open %s(%ld)\n", fpath, PTR_ERR(file)); ++ return file; ++ } ++ ++ /* keep file count */ ++ err = 0; ++ d = file->f_path.dentry; ++ h_parent = au_dget_parent_lock(d, AuLsc_I_PARENT); ++ if (!wbrtop) ++ mutex_unlock(&mtx); ++ /* mnt_want_write() is unnecessary here */ ++ h_dir = d_inode(h_parent); ++ inode = file_inode(file); ++ /* no delegation since it is just created */ ++ if (inode->i_nlink) ++ err = vfsub_unlink(h_dir, &file->f_path, /*delegated*/NULL, ++ /*force*/0); ++ inode_unlock(h_dir); ++ dput(h_parent); ++ if (unlikely(err)) { ++ if (!silent) ++ pr_err("unlink %s(%d)\n", fpath, err); ++ goto out; ++ } ++ ++ err = -EINVAL; ++ if (unlikely(sb && sb == d->d_sb)) { ++ if (!silent) ++ pr_err("%s must be outside\n", fpath); ++ goto out; ++ } ++ if (unlikely(au_test_fs_bad_xino(d->d_sb))) { ++ if (!silent) ++ pr_err("xino doesn't support %s(%s)\n", ++ fpath, au_sbtype(d->d_sb)); ++ goto out; ++ } ++ return file; /* success */ ++ ++out: ++ fput(file); ++ file = ERR_PTR(err); ++ return file; ++} ++ ++/* ++ * create a new xinofile at the same place/path as @base. ++ */ ++struct file *au_xino_create2(struct super_block *sb, struct path *base, ++ struct file *copy_src) ++{ ++ struct file *file; ++ struct dentry *dentry; ++ struct inode *dir, *delegated; ++ struct qstr *name; ++ struct path ppath, path; ++ int err, do_unlock; ++ struct au_xino_lock_dir ldir; ++ ++ do_unlock = 1; ++ au_xino_lock_dir(sb, base, &ldir); ++ dentry = base->dentry; ++ ppath.dentry = dentry->d_parent; /* dir inode is locked */ ++ ppath.mnt = base->mnt; ++ dir = d_inode(ppath.dentry); ++ IMustLock(dir); ++ ++ name = &dentry->d_name; ++ path.dentry = vfsub_lookup_one_len(name->name, &ppath, name->len); ++ if (IS_ERR(path.dentry)) { ++ file = (void *)path.dentry; ++ pr_err("%pd lookup err %ld\n", dentry, PTR_ERR(path.dentry)); ++ goto out; ++ } ++ ++ /* no need to mnt_want_write() since we call dentry_open() later */ ++ err = vfs_create(mnt_user_ns(base->mnt), dir, path.dentry, 0666, NULL); ++ if (unlikely(err)) { ++ file = ERR_PTR(err); ++ pr_err("%pd create err %d\n", dentry, err); ++ goto out_dput; ++ } ++ ++ path.mnt = base->mnt; ++ file = vfsub_dentry_open(&path, ++ O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE ++ /* | __FMODE_NONOTIFY */); ++ if (IS_ERR(file)) { ++ pr_err("%pd open err %ld\n", dentry, PTR_ERR(file)); ++ goto out_dput; ++ } ++ ++ delegated = NULL; ++ err = vfsub_unlink(dir, &file->f_path, &delegated, /*force*/0); ++ au_xino_unlock_dir(&ldir); ++ do_unlock = 0; ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ if (unlikely(err)) { ++ pr_err("%pd unlink err %d\n", dentry, err); ++ goto out_fput; ++ } ++ ++ if (copy_src) { ++ /* no one can touch copy_src xino */ ++ err = au_copy_file(file, copy_src, vfsub_f_size_read(copy_src)); ++ if (unlikely(err)) { ++ pr_err("%pd copy err %d\n", dentry, err); ++ goto out_fput; ++ } ++ } ++ goto out_dput; /* success */ ++ ++out_fput: ++ fput(file); ++ file = ERR_PTR(err); ++out_dput: ++ dput(path.dentry); ++out: ++ if (do_unlock) ++ au_xino_unlock_dir(&ldir); ++ return file; ++} ++ ++struct file *au_xino_file1(struct au_xino *xi) ++{ ++ struct file *file; ++ unsigned int u, nfile; ++ ++ file = NULL; ++ nfile = xi->xi_nfile; ++ for (u = 0; u < nfile; u++) { ++ file = xi->xi_file[u]; ++ if (file) ++ break; ++ } ++ ++ return file; ++} ++ ++static int au_xino_file_set(struct au_xino *xi, int idx, struct file *file) ++{ ++ int err; ++ struct file *f; ++ void *p; ++ ++ if (file) ++ get_file(file); ++ ++ err = 0; ++ f = NULL; ++ if (idx < xi->xi_nfile) { ++ f = xi->xi_file[idx]; ++ if (f) ++ fput(f); ++ } else { ++ p = au_kzrealloc(xi->xi_file, ++ sizeof(*xi->xi_file) * xi->xi_nfile, ++ sizeof(*xi->xi_file) * (idx + 1), ++ GFP_NOFS, /*may_shrink*/0); ++ if (p) { ++ MtxMustLock(&xi->xi_mtx); ++ xi->xi_file = p; ++ xi->xi_nfile = idx + 1; ++ } else { ++ err = -ENOMEM; ++ if (file) ++ fput(file); ++ goto out; ++ } ++ } ++ xi->xi_file[idx] = file; ++ ++out: ++ return err; ++} ++ ++/* ++ * if @xinew->xi is not set, then create new xigen file. ++ */ ++struct file *au_xi_new(struct super_block *sb, struct au_xi_new *xinew) ++{ ++ struct file *file; ++ int err; ++ ++ SiMustAnyLock(sb); ++ ++ file = au_xino_create2(sb, xinew->base, xinew->copy_src); ++ if (IS_ERR(file)) { ++ err = PTR_ERR(file); ++ pr_err("%s[%d], err %d\n", ++ xinew->xi ? "xino" : "xigen", ++ xinew->idx, err); ++ goto out; ++ } ++ ++ if (xinew->xi) ++ err = au_xino_file_set(xinew->xi, xinew->idx, file); ++ else { ++ BUG(); ++ /* todo: make xigen file an array */ ++ /* err = au_xigen_file_set(sb, xinew->idx, file); */ ++ } ++ fput(file); ++ if (unlikely(err)) ++ file = ERR_PTR(err); ++ ++out: ++ return file; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * truncate xino files ++ */ ++static int au_xino_do_trunc(struct super_block *sb, aufs_bindex_t bindex, ++ int idx, struct kstatfs *st) ++{ ++ int err; ++ blkcnt_t blocks; ++ struct file *file, *new_xino; ++ struct au_xi_new xinew = { ++ .idx = idx ++ }; ++ ++ err = 0; ++ xinew.xi = au_sbr(sb, bindex)->br_xino; ++ file = au_xino_file(xinew.xi, idx); ++ if (!file) ++ goto out; ++ ++ xinew.base = &file->f_path; ++ err = vfs_statfs(xinew.base, st); ++ if (unlikely(err)) { ++ AuErr1("statfs err %d, ignored\n", err); ++ err = 0; ++ goto out; ++ } ++ ++ blocks = file_inode(file)->i_blocks; ++ pr_info("begin truncating xino(b%d-%d), ib%llu, %llu/%llu free blks\n", ++ bindex, idx, (u64)blocks, st->f_bfree, st->f_blocks); ++ ++ xinew.copy_src = file; ++ new_xino = au_xi_new(sb, &xinew); ++ if (IS_ERR(new_xino)) { ++ err = PTR_ERR(new_xino); ++ pr_err("xino(b%d-%d), err %d, ignored\n", bindex, idx, err); ++ goto out; ++ } ++ ++ err = vfs_statfs(&new_xino->f_path, st); ++ if (!err) ++ pr_info("end truncating xino(b%d-%d), ib%llu, %llu/%llu free blks\n", ++ bindex, idx, (u64)file_inode(new_xino)->i_blocks, ++ st->f_bfree, st->f_blocks); ++ else { ++ AuErr1("statfs err %d, ignored\n", err); ++ err = 0; ++ } ++ ++out: ++ return err; ++} ++ ++int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex, int idx_begin) ++{ ++ int err, i; ++ unsigned long jiffy; ++ aufs_bindex_t bbot; ++ struct kstatfs *st; ++ struct au_branch *br; ++ struct au_xino *xi; ++ ++ err = -ENOMEM; ++ st = kmalloc(sizeof(*st), GFP_NOFS); ++ if (unlikely(!st)) ++ goto out; ++ ++ err = -EINVAL; ++ bbot = au_sbbot(sb); ++ if (unlikely(bindex < 0 || bbot < bindex)) ++ goto out_st; ++ ++ err = 0; ++ jiffy = jiffies; ++ br = au_sbr(sb, bindex); ++ xi = br->br_xino; ++ for (i = idx_begin; !err && i < xi->xi_nfile; i++) ++ err = au_xino_do_trunc(sb, bindex, i, st); ++ if (!err) ++ au_sbi(sb)->si_xino_jiffy = jiffy; ++ ++out_st: ++ au_kfree_rcu(st); ++out: ++ return err; ++} ++ ++struct xino_do_trunc_args { ++ struct super_block *sb; ++ struct au_branch *br; ++ int idx; ++}; ++ ++static void xino_do_trunc(void *_args) ++{ ++ struct xino_do_trunc_args *args = _args; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct inode *dir; ++ int err, idx; ++ aufs_bindex_t bindex; ++ ++ err = 0; ++ sb = args->sb; ++ dir = d_inode(sb->s_root); ++ br = args->br; ++ idx = args->idx; ++ ++ si_noflush_write_lock(sb); ++ ii_read_lock_parent(dir); ++ bindex = au_br_index(sb, br->br_id); ++ err = au_xino_trunc(sb, bindex, idx); ++ ii_read_unlock(dir); ++ if (unlikely(err)) ++ pr_warn("err b%d, (%d)\n", bindex, err); ++ atomic_dec(&br->br_xino->xi_truncating); ++ au_lcnt_dec(&br->br_count); ++ si_write_unlock(sb); ++ au_nwt_done(&au_sbi(sb)->si_nowait); ++ au_kfree_rcu(args); ++} ++ ++/* ++ * returns the index in the xi_file array whose corresponding file is necessary ++ * to truncate, or -1 which means no need to truncate. ++ */ ++static int xino_trunc_test(struct super_block *sb, struct au_branch *br) ++{ ++ int err; ++ unsigned int u; ++ struct kstatfs st; ++ struct au_sbinfo *sbinfo; ++ struct au_xino *xi; ++ struct file *file; ++ ++ /* todo: si_xino_expire and the ratio should be customizable */ ++ sbinfo = au_sbi(sb); ++ if (time_before(jiffies, ++ sbinfo->si_xino_jiffy + sbinfo->si_xino_expire)) ++ return -1; ++ ++ /* truncation border */ ++ xi = br->br_xino; ++ for (u = 0; u < xi->xi_nfile; u++) { ++ file = au_xino_file(xi, u); ++ if (!file) ++ continue; ++ ++ err = vfs_statfs(&file->f_path, &st); ++ if (unlikely(err)) { ++ AuErr1("statfs err %d, ignored\n", err); ++ return -1; ++ } ++ if (div64_u64(st.f_bfree * 100, st.f_blocks) ++ >= AUFS_XINO_DEF_TRUNC) ++ return u; ++ } ++ ++ return -1; ++} ++ ++static void xino_try_trunc(struct super_block *sb, struct au_branch *br) ++{ ++ int idx; ++ struct xino_do_trunc_args *args; ++ int wkq_err; ++ ++ idx = xino_trunc_test(sb, br); ++ if (idx < 0) ++ return; ++ ++ if (atomic_inc_return(&br->br_xino->xi_truncating) > 1) ++ goto out; ++ ++ /* lock and kfree() will be called in trunc_xino() */ ++ args = kmalloc(sizeof(*args), GFP_NOFS); ++ if (unlikely(!args)) { ++ AuErr1("no memory\n"); ++ goto out; ++ } ++ ++ au_lcnt_inc(&br->br_count); ++ args->sb = sb; ++ args->br = br; ++ args->idx = idx; ++ wkq_err = au_wkq_nowait(xino_do_trunc, args, sb, /*flags*/0); ++ if (!wkq_err) ++ return; /* success */ ++ ++ pr_err("wkq %d\n", wkq_err); ++ au_lcnt_dec(&br->br_count); ++ au_kfree_rcu(args); ++ ++out: ++ atomic_dec(&br->br_xino->xi_truncating); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_xi_calc { ++ int idx; ++ loff_t pos; ++}; ++ ++static void au_xi_calc(struct super_block *sb, ino_t h_ino, ++ struct au_xi_calc *calc) ++{ ++ loff_t maxent; ++ ++ maxent = au_xi_maxent(sb); ++ calc->idx = div64_u64_rem(h_ino, maxent, &calc->pos); ++ calc->pos *= sizeof(ino_t); ++} ++ ++static int au_xino_do_new_async(struct super_block *sb, struct au_branch *br, ++ struct au_xi_calc *calc) ++{ ++ int err; ++ struct file *file; ++ struct au_xino *xi = br->br_xino; ++ struct au_xi_new xinew = { ++ .xi = xi ++ }; ++ ++ SiMustAnyLock(sb); ++ ++ err = 0; ++ if (!xi) ++ goto out; ++ ++ mutex_lock(&xi->xi_mtx); ++ file = au_xino_file(xi, calc->idx); ++ if (file) ++ goto out_mtx; ++ ++ file = au_xino_file(xi, /*idx*/-1); ++ AuDebugOn(!file); ++ xinew.idx = calc->idx; ++ xinew.base = &file->f_path; ++ /* xinew.copy_src = NULL; */ ++ file = au_xi_new(sb, &xinew); ++ if (IS_ERR(file)) ++ err = PTR_ERR(file); ++ ++out_mtx: ++ mutex_unlock(&xi->xi_mtx); ++out: ++ return err; ++} ++ ++struct au_xino_do_new_async_args { ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_xi_calc calc; ++ ino_t ino; ++}; ++ ++struct au_xi_writing { ++ struct hlist_bl_node node; ++ ino_t h_ino, ino; ++}; ++ ++static int au_xino_do_write(struct file *file, struct au_xi_calc *calc, ++ ino_t ino); ++ ++static void au_xino_call_do_new_async(void *args) ++{ ++ struct au_xino_do_new_async_args *a = args; ++ struct au_branch *br; ++ struct super_block *sb; ++ struct au_sbinfo *sbi; ++ struct inode *root; ++ struct file *file; ++ struct au_xi_writing *del, *p; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ int err; ++ ++ br = a->br; ++ sb = a->sb; ++ sbi = au_sbi(sb); ++ si_noflush_read_lock(sb); ++ root = d_inode(sb->s_root); ++ ii_read_lock_child(root); ++ err = au_xino_do_new_async(sb, br, &a->calc); ++ if (unlikely(err)) { ++ AuIOErr("err %d\n", err); ++ goto out; ++ } ++ ++ file = au_xino_file(br->br_xino, a->calc.idx); ++ AuDebugOn(!file); ++ err = au_xino_do_write(file, &a->calc, a->ino); ++ if (unlikely(err)) { ++ AuIOErr("err %d\n", err); ++ goto out; ++ } ++ ++ del = NULL; ++ hbl = &br->br_xino->xi_writing; ++ hlist_bl_lock(hbl); ++ au_hbl_for_each(pos, hbl) { ++ p = container_of(pos, struct au_xi_writing, node); ++ if (p->ino == a->ino) { ++ del = p; ++ hlist_bl_del(&p->node); ++ break; ++ } ++ } ++ hlist_bl_unlock(hbl); ++ au_kfree_rcu(del); ++ ++out: ++ au_lcnt_dec(&br->br_count); ++ ii_read_unlock(root); ++ si_read_unlock(sb); ++ au_nwt_done(&sbi->si_nowait); ++ au_kfree_rcu(a); ++} ++ ++/* ++ * create a new xino file asynchronously ++ */ ++static int au_xino_new_async(struct super_block *sb, struct au_branch *br, ++ struct au_xi_calc *calc, ino_t ino) ++{ ++ int err; ++ struct au_xino_do_new_async_args *arg; ++ ++ err = -ENOMEM; ++ arg = kmalloc(sizeof(*arg), GFP_NOFS); ++ if (unlikely(!arg)) ++ goto out; ++ ++ arg->sb = sb; ++ arg->br = br; ++ arg->calc = *calc; ++ arg->ino = ino; ++ au_lcnt_inc(&br->br_count); ++ err = au_wkq_nowait(au_xino_call_do_new_async, arg, sb, AuWkq_NEST); ++ if (unlikely(err)) { ++ pr_err("wkq %d\n", err); ++ au_lcnt_dec(&br->br_count); ++ au_kfree_rcu(arg); ++ } ++ ++out: ++ return err; ++} ++ ++/* ++ * read @ino from xinofile for the specified branch{@sb, @bindex} ++ * at the position of @h_ino. ++ */ ++int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t *ino) ++{ ++ int err; ++ ssize_t sz; ++ struct au_xi_calc calc; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ struct au_xino *xi; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_xi_writing *p; ++ ++ *ino = 0; ++ if (!au_opt_test(au_mntflags(sb), XINO)) ++ return 0; /* no xino */ ++ ++ err = 0; ++ au_xi_calc(sb, h_ino, &calc); ++ xi = au_sbr(sb, bindex)->br_xino; ++ file = au_xino_file(xi, calc.idx); ++ if (!file) { ++ hbl = &xi->xi_writing; ++ hlist_bl_lock(hbl); ++ au_hbl_for_each(pos, hbl) { ++ p = container_of(pos, struct au_xi_writing, node); ++ if (p->h_ino == h_ino) { ++ AuDbg("hi%llu, i%llu, found\n", ++ (u64)p->h_ino, (u64)p->ino); ++ *ino = p->ino; ++ break; ++ } ++ } ++ hlist_bl_unlock(hbl); ++ return 0; ++ } else if (vfsub_f_size_read(file) < calc.pos + sizeof(*ino)) ++ return 0; /* no xino */ ++ ++ sbinfo = au_sbi(sb); ++ sz = xino_fread(file, ino, sizeof(*ino), &calc.pos); ++ if (sz == sizeof(*ino)) ++ return 0; /* success */ ++ ++ err = sz; ++ if (unlikely(sz >= 0)) { ++ err = -EIO; ++ AuIOErr("xino read error (%zd)\n", sz); ++ } ++ return err; ++} ++ ++static int au_xino_do_write(struct file *file, struct au_xi_calc *calc, ++ ino_t ino) ++{ ++ ssize_t sz; ++ ++ sz = xino_fwrite(file, &ino, sizeof(ino), &calc->pos); ++ if (sz == sizeof(ino)) ++ return 0; /* success */ ++ ++ AuIOErr("write failed (%zd)\n", sz); ++ return -EIO; ++} ++ ++/* ++ * write @ino to the xinofile for the specified branch{@sb, @bindex} ++ * at the position of @h_ino. ++ * even if @ino is zero, it is written to the xinofile and means no entry. ++ * if the size of the xino file on a specific filesystem exceeds the watermark, ++ * try truncating it. ++ */ ++int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t ino) ++{ ++ int err; ++ unsigned int mnt_flags; ++ struct au_xi_calc calc; ++ struct file *file; ++ struct au_branch *br; ++ struct au_xino *xi; ++ struct au_xi_writing *p; ++ ++ SiMustAnyLock(sb); ++ ++ mnt_flags = au_mntflags(sb); ++ if (!au_opt_test(mnt_flags, XINO)) ++ return 0; ++ ++ au_xi_calc(sb, h_ino, &calc); ++ br = au_sbr(sb, bindex); ++ xi = br->br_xino; ++ file = au_xino_file(xi, calc.idx); ++ if (!file) { ++ /* store the inum pair into the list */ ++ p = kmalloc(sizeof(*p), GFP_NOFS | __GFP_NOFAIL); ++ p->h_ino = h_ino; ++ p->ino = ino; ++ au_hbl_add(&p->node, &xi->xi_writing); ++ ++ /* create and write a new xino file asynchronously */ ++ err = au_xino_new_async(sb, br, &calc, ino); ++ if (!err) ++ return 0; /* success */ ++ goto out; ++ } ++ ++ err = au_xino_do_write(file, &calc, ino); ++ if (!err) { ++ br = au_sbr(sb, bindex); ++ if (au_opt_test(mnt_flags, TRUNC_XINO) ++ && au_test_fs_trunc_xino(au_br_sb(br))) ++ xino_try_trunc(sb, br); ++ return 0; /* success */ ++ } ++ ++out: ++ AuIOErr("write failed (%d)\n", err); ++ return -EIO; ++} ++ ++static ssize_t xino_fread_wkq(struct file *file, void *buf, size_t size, ++ loff_t *pos); ++ ++/* todo: unnecessary to support mmap_sem since kernel-space? */ ++ssize_t xino_fread(struct file *file, void *kbuf, size_t size, loff_t *pos) ++{ ++ ssize_t err; ++ int i; ++ const int prevent_endless = 10; ++ ++ i = 0; ++ do { ++ err = vfsub_read_k(file, kbuf, size, pos); ++ if (err == -EINTR ++ && !au_wkq_test() ++ && fatal_signal_pending(current)) { ++ err = xino_fread_wkq(file, kbuf, size, pos); ++ BUG_ON(err == -EINTR); ++ } ++ } while (i++ < prevent_endless ++ && (err == -EAGAIN || err == -EINTR)); ++ ++#if 0 /* reserved for future use */ ++ if (err > 0) ++ fsnotify_access(file->f_path.dentry); ++#endif ++ ++ return err; ++} ++ ++struct xino_fread_args { ++ ssize_t *errp; ++ struct file *file; ++ void *buf; ++ size_t size; ++ loff_t *pos; ++}; ++ ++static void call_xino_fread(void *args) ++{ ++ struct xino_fread_args *a = args; ++ *a->errp = xino_fread(a->file, a->buf, a->size, a->pos); ++} ++ ++static ssize_t xino_fread_wkq(struct file *file, void *buf, size_t size, ++ loff_t *pos) ++{ ++ ssize_t err; ++ int wkq_err; ++ struct xino_fread_args args = { ++ .errp = &err, ++ .file = file, ++ .buf = buf, ++ .size = size, ++ .pos = pos ++ }; ++ ++ wkq_err = au_wkq_wait(call_xino_fread, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ ++ return err; ++} ++ ++static ssize_t xino_fwrite_wkq(struct file *file, void *buf, size_t size, ++ loff_t *pos); ++ ++static ssize_t do_xino_fwrite(struct file *file, void *kbuf, size_t size, ++ loff_t *pos) ++{ ++ ssize_t err; ++ int i; ++ const int prevent_endless = 10; ++ ++ i = 0; ++ do { ++ err = vfsub_write_k(file, kbuf, size, pos); ++ if (err == -EINTR ++ && !au_wkq_test() ++ && fatal_signal_pending(current)) { ++ err = xino_fwrite_wkq(file, kbuf, size, pos); ++ BUG_ON(err == -EINTR); ++ } ++ } while (i++ < prevent_endless ++ && (err == -EAGAIN || err == -EINTR)); ++ ++#if 0 /* reserved for future use */ ++ if (err > 0) ++ fsnotify_modify(file->f_path.dentry); ++#endif ++ ++ return err; ++} ++ ++struct do_xino_fwrite_args { ++ ssize_t *errp; ++ struct file *file; ++ void *buf; ++ size_t size; ++ loff_t *pos; ++}; ++ ++static void call_do_xino_fwrite(void *args) ++{ ++ struct do_xino_fwrite_args *a = args; ++ *a->errp = do_xino_fwrite(a->file, a->buf, a->size, a->pos); ++} ++ ++static ssize_t xino_fwrite_wkq(struct file *file, void *buf, size_t size, ++ loff_t *pos) ++{ ++ ssize_t err; ++ int wkq_err; ++ struct do_xino_fwrite_args args = { ++ .errp = &err, ++ .file = file, ++ .buf = buf, ++ .size = size, ++ .pos = pos ++ }; ++ ++ /* ++ * it breaks RLIMIT_FSIZE and normal user's limit, ++ * users should care about quota and real 'filesystem full.' ++ */ ++ wkq_err = au_wkq_wait(call_do_xino_fwrite, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ ++ return err; ++} ++ ++ssize_t xino_fwrite(struct file *file, void *buf, size_t size, loff_t *pos) ++{ ++ ssize_t err; ++ ++ if (rlimit(RLIMIT_FSIZE) == RLIM_INFINITY) { ++ lockdep_off(); ++ err = do_xino_fwrite(file, buf, size, pos); ++ lockdep_on(); ++ } else { ++ lockdep_off(); ++ err = xino_fwrite_wkq(file, buf, size, pos); ++ lockdep_on(); ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * inode number bitmap ++ */ ++static const int page_bits = (int)PAGE_SIZE * BITS_PER_BYTE; ++static ino_t xib_calc_ino(unsigned long pindex, int bit) ++{ ++ ino_t ino; ++ ++ AuDebugOn(bit < 0 || page_bits <= bit); ++ ino = AUFS_FIRST_INO + pindex * page_bits + bit; ++ return ino; ++} ++ ++static void xib_calc_bit(ino_t ino, unsigned long *pindex, int *bit) ++{ ++ AuDebugOn(ino < AUFS_FIRST_INO); ++ ino -= AUFS_FIRST_INO; ++ *pindex = ino / page_bits; ++ *bit = ino % page_bits; ++} ++ ++static int xib_pindex(struct super_block *sb, unsigned long pindex) ++{ ++ int err; ++ loff_t pos; ++ ssize_t sz; ++ struct au_sbinfo *sbinfo; ++ struct file *xib; ++ unsigned long *p; ++ ++ sbinfo = au_sbi(sb); ++ MtxMustLock(&sbinfo->si_xib_mtx); ++ AuDebugOn(pindex > ULONG_MAX / PAGE_SIZE ++ || !au_opt_test(sbinfo->si_mntflags, XINO)); ++ ++ if (pindex == sbinfo->si_xib_last_pindex) ++ return 0; ++ ++ xib = sbinfo->si_xib; ++ p = sbinfo->si_xib_buf; ++ pos = sbinfo->si_xib_last_pindex; ++ pos *= PAGE_SIZE; ++ sz = xino_fwrite(xib, p, PAGE_SIZE, &pos); ++ if (unlikely(sz != PAGE_SIZE)) ++ goto out; ++ ++ pos = pindex; ++ pos *= PAGE_SIZE; ++ if (vfsub_f_size_read(xib) >= pos + PAGE_SIZE) ++ sz = xino_fread(xib, p, PAGE_SIZE, &pos); ++ else { ++ memset(p, 0, PAGE_SIZE); ++ sz = xino_fwrite(xib, p, PAGE_SIZE, &pos); ++ } ++ if (sz == PAGE_SIZE) { ++ sbinfo->si_xib_last_pindex = pindex; ++ return 0; /* success */ ++ } ++ ++out: ++ AuIOErr1("write failed (%zd)\n", sz); ++ err = sz; ++ if (sz >= 0) ++ err = -EIO; ++ return err; ++} ++ ++static void au_xib_clear_bit(struct inode *inode) ++{ ++ int err, bit; ++ unsigned long pindex; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ ++ AuDebugOn(inode->i_nlink); ++ ++ sb = inode->i_sb; ++ xib_calc_bit(inode->i_ino, &pindex, &bit); ++ AuDebugOn(page_bits <= bit); ++ sbinfo = au_sbi(sb); ++ mutex_lock(&sbinfo->si_xib_mtx); ++ err = xib_pindex(sb, pindex); ++ if (!err) { ++ clear_bit(bit, sbinfo->si_xib_buf); ++ sbinfo->si_xib_next_bit = bit; ++ } ++ mutex_unlock(&sbinfo->si_xib_mtx); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * truncate a xino bitmap file ++ */ ++ ++/* todo: slow */ ++static int do_xib_restore(struct super_block *sb, struct file *file, void *page) ++{ ++ int err, bit; ++ ssize_t sz; ++ unsigned long pindex; ++ loff_t pos, pend; ++ struct au_sbinfo *sbinfo; ++ ino_t *ino; ++ unsigned long *p; ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ MtxMustLock(&sbinfo->si_xib_mtx); ++ p = sbinfo->si_xib_buf; ++ pend = vfsub_f_size_read(file); ++ pos = 0; ++ while (pos < pend) { ++ sz = xino_fread(file, page, PAGE_SIZE, &pos); ++ err = sz; ++ if (unlikely(sz <= 0)) ++ goto out; ++ ++ err = 0; ++ for (ino = page; sz > 0; ino++, sz -= sizeof(ino)) { ++ if (unlikely(*ino < AUFS_FIRST_INO)) ++ continue; ++ ++ xib_calc_bit(*ino, &pindex, &bit); ++ AuDebugOn(page_bits <= bit); ++ err = xib_pindex(sb, pindex); ++ if (!err) ++ set_bit(bit, p); ++ else ++ goto out; ++ } ++ } ++ ++out: ++ return err; ++} ++ ++static int xib_restore(struct super_block *sb) ++{ ++ int err, i; ++ unsigned int nfile; ++ aufs_bindex_t bindex, bbot; ++ void *page; ++ struct au_branch *br; ++ struct au_xino *xi; ++ struct file *file; ++ ++ err = -ENOMEM; ++ page = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!page)) ++ goto out; ++ ++ err = 0; ++ bbot = au_sbbot(sb); ++ for (bindex = 0; !err && bindex <= bbot; bindex++) ++ if (!bindex || is_sb_shared(sb, bindex, bindex - 1) < 0) { ++ br = au_sbr(sb, bindex); ++ xi = br->br_xino; ++ nfile = xi->xi_nfile; ++ for (i = 0; i < nfile; i++) { ++ file = au_xino_file(xi, i); ++ if (file) ++ err = do_xib_restore(sb, file, page); ++ } ++ } else ++ AuDbg("skip shared b%d\n", bindex); ++ free_page((unsigned long)page); ++ ++out: ++ return err; ++} ++ ++int au_xib_trunc(struct super_block *sb) ++{ ++ int err; ++ ssize_t sz; ++ loff_t pos; ++ struct au_sbinfo *sbinfo; ++ unsigned long *p; ++ struct file *file; ++ ++ SiMustWriteLock(sb); ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ if (!au_opt_test(sbinfo->si_mntflags, XINO)) ++ goto out; ++ ++ file = sbinfo->si_xib; ++ if (vfsub_f_size_read(file) <= PAGE_SIZE) ++ goto out; ++ ++ file = au_xino_create2(sb, &sbinfo->si_xib->f_path, NULL); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ fput(sbinfo->si_xib); ++ sbinfo->si_xib = file; ++ ++ p = sbinfo->si_xib_buf; ++ memset(p, 0, PAGE_SIZE); ++ pos = 0; ++ sz = xino_fwrite(sbinfo->si_xib, p, PAGE_SIZE, &pos); ++ if (unlikely(sz != PAGE_SIZE)) { ++ err = sz; ++ AuIOErr("err %d\n", err); ++ if (sz >= 0) ++ err = -EIO; ++ goto out; ++ } ++ ++ mutex_lock(&sbinfo->si_xib_mtx); ++ /* mnt_want_write() is unnecessary here */ ++ err = xib_restore(sb); ++ mutex_unlock(&sbinfo->si_xib_mtx); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_xino *au_xino_alloc(unsigned int nfile) ++{ ++ struct au_xino *xi; ++ ++ xi = kzalloc(sizeof(*xi), GFP_NOFS); ++ if (unlikely(!xi)) ++ goto out; ++ xi->xi_nfile = nfile; ++ xi->xi_file = kcalloc(nfile, sizeof(*xi->xi_file), GFP_NOFS); ++ if (unlikely(!xi->xi_file)) ++ goto out_free; ++ ++ xi->xi_nondir.total = 8; /* initial size */ ++ xi->xi_nondir.array = kcalloc(xi->xi_nondir.total, sizeof(ino_t), ++ GFP_NOFS); ++ if (unlikely(!xi->xi_nondir.array)) ++ goto out_file; ++ ++ spin_lock_init(&xi->xi_nondir.spin); ++ init_waitqueue_head(&xi->xi_nondir.wqh); ++ mutex_init(&xi->xi_mtx); ++ INIT_HLIST_BL_HEAD(&xi->xi_writing); ++ atomic_set(&xi->xi_truncating, 0); ++ kref_init(&xi->xi_kref); ++ goto out; /* success */ ++ ++out_file: ++ au_kfree_try_rcu(xi->xi_file); ++out_free: ++ au_kfree_rcu(xi); ++ xi = NULL; ++out: ++ return xi; ++} ++ ++static int au_xino_init(struct au_branch *br, int idx, struct file *file) ++{ ++ int err; ++ struct au_xino *xi; ++ ++ err = 0; ++ xi = au_xino_alloc(idx + 1); ++ if (unlikely(!xi)) { ++ err = -ENOMEM; ++ goto out; ++ } ++ ++ if (file) ++ get_file(file); ++ xi->xi_file[idx] = file; ++ AuDebugOn(br->br_xino); ++ br->br_xino = xi; ++ ++out: ++ return err; ++} ++ ++static void au_xino_release(struct kref *kref) ++{ ++ struct au_xino *xi; ++ int i; ++ unsigned long ul; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos, *n; ++ struct au_xi_writing *p; ++ ++ xi = container_of(kref, struct au_xino, xi_kref); ++ for (i = 0; i < xi->xi_nfile; i++) ++ if (xi->xi_file[i]) ++ fput(xi->xi_file[i]); ++ for (i = xi->xi_nondir.total - 1; i >= 0; i--) ++ AuDebugOn(xi->xi_nondir.array[i]); ++ mutex_destroy(&xi->xi_mtx); ++ hbl = &xi->xi_writing; ++ ul = au_hbl_count(hbl); ++ if (unlikely(ul)) { ++ pr_warn("xi_writing %lu\n", ul); ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry_safe(p, pos, n, hbl, node) { ++ hlist_bl_del(&p->node); ++ /* kmemleak reported au_kfree_rcu() doesn't free it */ ++ kfree(p); ++ } ++ hlist_bl_unlock(hbl); ++ } ++ au_kfree_try_rcu(xi->xi_file); ++ au_kfree_try_rcu(xi->xi_nondir.array); ++ au_kfree_rcu(xi); ++} ++ ++int au_xino_put(struct au_branch *br) ++{ ++ int ret; ++ struct au_xino *xi; ++ ++ ret = 0; ++ xi = br->br_xino; ++ if (xi) { ++ br->br_xino = NULL; ++ ret = kref_put(&xi->xi_kref, au_xino_release); ++ } ++ ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * xino mount option handlers ++ */ ++ ++/* xino bitmap */ ++static void xino_clear_xib(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ if (sbinfo->si_xib) ++ fput(sbinfo->si_xib); ++ sbinfo->si_xib = NULL; ++ if (sbinfo->si_xib_buf) ++ free_page((unsigned long)sbinfo->si_xib_buf); ++ sbinfo->si_xib_buf = NULL; ++} ++ ++static int au_xino_set_xib(struct super_block *sb, struct path *path) ++{ ++ int err; ++ loff_t pos; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ struct super_block *xi_sb; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ file = au_xino_create2(sb, path, sbinfo->si_xib); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ if (sbinfo->si_xib) ++ fput(sbinfo->si_xib); ++ sbinfo->si_xib = file; ++ xi_sb = file_inode(file)->i_sb; ++ sbinfo->si_ximaxent = xi_sb->s_maxbytes; ++ if (unlikely(sbinfo->si_ximaxent < PAGE_SIZE)) { ++ err = -EIO; ++ pr_err("s_maxbytes(%llu) on %s is too small\n", ++ (u64)sbinfo->si_ximaxent, au_sbtype(xi_sb)); ++ goto out_unset; ++ } ++ sbinfo->si_ximaxent /= sizeof(ino_t); ++ ++ err = -ENOMEM; ++ if (!sbinfo->si_xib_buf) ++ sbinfo->si_xib_buf = (void *)get_zeroed_page(GFP_NOFS); ++ if (unlikely(!sbinfo->si_xib_buf)) ++ goto out_unset; ++ ++ sbinfo->si_xib_last_pindex = 0; ++ sbinfo->si_xib_next_bit = 0; ++ if (vfsub_f_size_read(file) < PAGE_SIZE) { ++ pos = 0; ++ err = xino_fwrite(file, sbinfo->si_xib_buf, PAGE_SIZE, &pos); ++ if (unlikely(err != PAGE_SIZE)) ++ goto out_free; ++ } ++ err = 0; ++ goto out; /* success */ ++ ++out_free: ++ if (sbinfo->si_xib_buf) ++ free_page((unsigned long)sbinfo->si_xib_buf); ++ sbinfo->si_xib_buf = NULL; ++ if (err >= 0) ++ err = -EIO; ++out_unset: ++ fput(sbinfo->si_xib); ++ sbinfo->si_xib = NULL; ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* xino for each branch */ ++static void xino_clear_br(struct super_block *sb) ++{ ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ AuDebugOn(!br); ++ au_xino_put(br); ++ } ++} ++ ++static void au_xino_set_br_shared(struct super_block *sb, struct au_branch *br, ++ aufs_bindex_t bshared) ++{ ++ struct au_branch *brshared; ++ ++ brshared = au_sbr(sb, bshared); ++ AuDebugOn(!brshared->br_xino); ++ AuDebugOn(!brshared->br_xino->xi_file); ++ if (br->br_xino != brshared->br_xino) { ++ au_xino_get(brshared); ++ au_xino_put(br); ++ br->br_xino = brshared->br_xino; ++ } ++} ++ ++struct au_xino_do_set_br { ++ struct au_branch *br; ++ ino_t h_ino; ++ aufs_bindex_t bshared; ++}; ++ ++static int au_xino_do_set_br(struct super_block *sb, struct path *path, ++ struct au_xino_do_set_br *args) ++{ ++ int err; ++ struct au_xi_calc calc; ++ struct file *file; ++ struct au_branch *br; ++ struct au_xi_new xinew = { ++ .base = path ++ }; ++ ++ br = args->br; ++ xinew.xi = br->br_xino; ++ au_xi_calc(sb, args->h_ino, &calc); ++ xinew.copy_src = au_xino_file(xinew.xi, calc.idx); ++ if (args->bshared >= 0) ++ /* shared xino */ ++ au_xino_set_br_shared(sb, br, args->bshared); ++ else if (!xinew.xi) { ++ /* new xino */ ++ err = au_xino_init(br, calc.idx, xinew.copy_src); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ /* force re-creating */ ++ xinew.xi = br->br_xino; ++ xinew.idx = calc.idx; ++ mutex_lock(&xinew.xi->xi_mtx); ++ file = au_xi_new(sb, &xinew); ++ mutex_unlock(&xinew.xi->xi_mtx); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ AuDebugOn(!file); ++ ++ err = au_xino_do_write(file, &calc, AUFS_ROOT_INO); ++ if (unlikely(err)) ++ au_xino_put(br); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_xino_set_br(struct super_block *sb, struct path *path) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct au_xino_do_set_br args; ++ struct inode *inode; ++ ++ SiMustWriteLock(sb); ++ ++ bbot = au_sbbot(sb); ++ inode = d_inode(sb->s_root); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ args.h_ino = au_h_iptr(inode, bindex)->i_ino; ++ args.br = au_sbr(sb, bindex); ++ args.bshared = is_sb_shared(sb, bindex, bindex - 1); ++ err = au_xino_do_set_br(sb, path, &args); ++ if (unlikely(err)) ++ break; ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_xino_clr(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ au_xigen_clr(sb); ++ xino_clear_xib(sb); ++ xino_clear_br(sb); ++ dbgaufs_brs_del(sb, 0); ++ sbinfo = au_sbi(sb); ++ /* lvalue, do not call au_mntflags() */ ++ au_opt_clr(sbinfo->si_mntflags, XINO); ++} ++ ++int au_xino_set(struct super_block *sb, struct au_opt_xino *xiopt, int remount) ++{ ++ int err, skip; ++ struct dentry *dentry, *parent, *cur_dentry, *cur_parent; ++ struct qstr *dname, *cur_name; ++ struct file *cur_xino; ++ struct au_sbinfo *sbinfo; ++ struct path *path, *cur_path; ++ ++ SiMustWriteLock(sb); ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ path = &xiopt->file->f_path; ++ dentry = path->dentry; ++ parent = dget_parent(dentry); ++ if (remount) { ++ skip = 0; ++ cur_xino = sbinfo->si_xib; ++ if (cur_xino) { ++ cur_path = &cur_xino->f_path; ++ cur_dentry = cur_path->dentry; ++ cur_parent = dget_parent(cur_dentry); ++ cur_name = &cur_dentry->d_name; ++ dname = &dentry->d_name; ++ skip = (cur_parent == parent ++ && au_qstreq(dname, cur_name)); ++ dput(cur_parent); ++ } ++ if (skip) ++ goto out; ++ } ++ ++ au_opt_set(sbinfo->si_mntflags, XINO); ++ err = au_xino_set_xib(sb, path); ++ /* si_x{read,write} are set */ ++ if (!err) ++ err = au_xigen_set(sb, path); ++ if (!err) ++ err = au_xino_set_br(sb, path); ++ if (!err) { ++ dbgaufs_brs_add(sb, 0, /*topdown*/1); ++ goto out; /* success */ ++ } ++ ++ /* reset all */ ++ AuIOErr("failed setting xino(%d).\n", err); ++ au_xino_clr(sb); ++ ++out: ++ dput(parent); ++ return err; ++} ++ ++/* ++ * create a xinofile at the default place/path. ++ */ ++struct file *au_xino_def(struct super_block *sb) ++{ ++ struct file *file; ++ char *page, *p; ++ struct au_branch *br; ++ struct super_block *h_sb; ++ struct path path; ++ aufs_bindex_t bbot, bindex, bwr; ++ ++ br = NULL; ++ bbot = au_sbbot(sb); ++ bwr = -1; ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_writable(br->br_perm) ++ && !au_test_fs_bad_xino(au_br_sb(br))) { ++ bwr = bindex; ++ break; ++ } ++ } ++ ++ if (bwr >= 0) { ++ file = ERR_PTR(-ENOMEM); ++ page = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!page)) ++ goto out; ++ path.mnt = au_br_mnt(br); ++ path.dentry = au_h_dptr(sb->s_root, bwr); ++ p = d_path(&path, page, PATH_MAX - sizeof(AUFS_XINO_FNAME)); ++ file = (void *)p; ++ if (!IS_ERR(p)) { ++ strcat(p, "/" AUFS_XINO_FNAME); ++ AuDbg("%s\n", p); ++ file = au_xino_create(sb, p, /*silent*/0, /*wbrtop*/1); ++ } ++ free_page((unsigned long)page); ++ } else { ++ file = au_xino_create(sb, AUFS_XINO_DEFPATH, /*silent*/0, ++ /*wbrtop*/0); ++ if (IS_ERR(file)) ++ goto out; ++ h_sb = file->f_path.dentry->d_sb; ++ if (unlikely(au_test_fs_bad_xino(h_sb))) { ++ pr_err("xino doesn't support %s(%s)\n", ++ AUFS_XINO_DEFPATH, au_sbtype(h_sb)); ++ fput(file); ++ file = ERR_PTR(-EINVAL); ++ } ++ } ++ ++out: ++ return file; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * initialize the xinofile for the specified branch @br ++ * at the place/path where @base_file indicates. ++ * test whether another branch is on the same filesystem or not, ++ * if found then share the xinofile with another branch. ++ */ ++int au_xino_init_br(struct super_block *sb, struct au_branch *br, ino_t h_ino, ++ struct path *base) ++{ ++ int err; ++ struct au_xino_do_set_br args = { ++ .h_ino = h_ino, ++ .br = br ++ }; ++ ++ args.bshared = sbr_find_shared(sb, /*btop*/0, au_sbbot(sb), ++ au_br_sb(br)); ++ err = au_xino_do_set_br(sb, base, &args); ++ if (unlikely(err)) ++ au_xino_put(br); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * get an unused inode number from bitmap ++ */ ++ino_t au_xino_new_ino(struct super_block *sb) ++{ ++ ino_t ino; ++ unsigned long *p, pindex, ul, pend; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ int free_bit, err; ++ ++ if (!au_opt_test(au_mntflags(sb), XINO)) ++ return iunique(sb, AUFS_FIRST_INO); ++ ++ sbinfo = au_sbi(sb); ++ mutex_lock(&sbinfo->si_xib_mtx); ++ p = sbinfo->si_xib_buf; ++ free_bit = sbinfo->si_xib_next_bit; ++ if (free_bit < page_bits && !test_bit(free_bit, p)) ++ goto out; /* success */ ++ free_bit = find_first_zero_bit(p, page_bits); ++ if (free_bit < page_bits) ++ goto out; /* success */ ++ ++ pindex = sbinfo->si_xib_last_pindex; ++ for (ul = pindex - 1; ul < ULONG_MAX; ul--) { ++ err = xib_pindex(sb, ul); ++ if (unlikely(err)) ++ goto out_err; ++ free_bit = find_first_zero_bit(p, page_bits); ++ if (free_bit < page_bits) ++ goto out; /* success */ ++ } ++ ++ file = sbinfo->si_xib; ++ pend = vfsub_f_size_read(file) / PAGE_SIZE; ++ for (ul = pindex + 1; ul <= pend; ul++) { ++ err = xib_pindex(sb, ul); ++ if (unlikely(err)) ++ goto out_err; ++ free_bit = find_first_zero_bit(p, page_bits); ++ if (free_bit < page_bits) ++ goto out; /* success */ ++ } ++ BUG(); ++ ++out: ++ set_bit(free_bit, p); ++ sbinfo->si_xib_next_bit = free_bit + 1; ++ pindex = sbinfo->si_xib_last_pindex; ++ mutex_unlock(&sbinfo->si_xib_mtx); ++ ino = xib_calc_ino(pindex, free_bit); ++ AuDbg("i%lu\n", (unsigned long)ino); ++ return ino; ++out_err: ++ mutex_unlock(&sbinfo->si_xib_mtx); ++ AuDbg("i0\n"); ++ return 0; ++} ++ ++/* for s_op->delete_inode() */ ++void au_xino_delete_inode(struct inode *inode, const int unlinked) ++{ ++ int err; ++ unsigned int mnt_flags; ++ aufs_bindex_t bindex, bbot, bi; ++ unsigned char try_trunc; ++ struct au_iinfo *iinfo; ++ struct super_block *sb; ++ struct au_hinode *hi; ++ struct inode *h_inode; ++ struct au_branch *br; ++ struct au_xi_calc calc; ++ struct file *file; ++ ++ AuDebugOn(au_is_bad_inode(inode)); ++ ++ sb = inode->i_sb; ++ mnt_flags = au_mntflags(sb); ++ if (!au_opt_test(mnt_flags, XINO) ++ || inode->i_ino == AUFS_ROOT_INO) ++ return; ++ ++ if (unlinked) { ++ au_xigen_inc(inode); ++ au_xib_clear_bit(inode); ++ } ++ ++ iinfo = au_ii(inode); ++ bindex = iinfo->ii_btop; ++ if (bindex < 0) ++ return; ++ ++ try_trunc = !!au_opt_test(mnt_flags, TRUNC_XINO); ++ hi = au_hinode(iinfo, bindex); ++ bbot = iinfo->ii_bbot; ++ for (; bindex <= bbot; bindex++, hi++) { ++ h_inode = hi->hi_inode; ++ if (!h_inode ++ || (!unlinked && h_inode->i_nlink)) ++ continue; ++ ++ /* inode may not be revalidated */ ++ bi = au_br_index(sb, hi->hi_id); ++ if (bi < 0) ++ continue; ++ ++ br = au_sbr(sb, bi); ++ au_xi_calc(sb, h_inode->i_ino, &calc); ++ file = au_xino_file(br->br_xino, calc.idx); ++ if (IS_ERR_OR_NULL(file)) ++ continue; ++ ++ err = au_xino_do_write(file, &calc, /*ino*/0); ++ if (!err && try_trunc ++ && au_test_fs_trunc_xino(au_br_sb(br))) ++ xino_try_trunc(sb, br); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_xinondir_find(struct au_xino *xi, ino_t h_ino) ++{ ++ int found, total, i; ++ ++ found = -1; ++ total = xi->xi_nondir.total; ++ for (i = 0; i < total; i++) { ++ if (xi->xi_nondir.array[i] != h_ino) ++ continue; ++ found = i; ++ break; ++ } ++ ++ return found; ++} ++ ++static int au_xinondir_expand(struct au_xino *xi) ++{ ++ int err, sz; ++ ino_t *p; ++ ++ BUILD_BUG_ON(KMALLOC_MAX_SIZE > INT_MAX); ++ ++ err = -ENOMEM; ++ sz = xi->xi_nondir.total * sizeof(ino_t); ++ if (unlikely(sz > KMALLOC_MAX_SIZE / 2)) ++ goto out; ++ p = au_kzrealloc(xi->xi_nondir.array, sz, sz << 1, GFP_ATOMIC, ++ /*may_shrink*/0); ++ if (p) { ++ xi->xi_nondir.array = p; ++ xi->xi_nondir.total <<= 1; ++ AuDbg("xi_nondir.total %d\n", xi->xi_nondir.total); ++ err = 0; ++ } ++ ++out: ++ return err; ++} ++ ++void au_xinondir_leave(struct super_block *sb, aufs_bindex_t bindex, ++ ino_t h_ino, int idx) ++{ ++ struct au_xino *xi; ++ ++ AuDebugOn(!au_opt_test(au_mntflags(sb), XINO)); ++ xi = au_sbr(sb, bindex)->br_xino; ++ AuDebugOn(idx < 0 || xi->xi_nondir.total <= idx); ++ ++ spin_lock(&xi->xi_nondir.spin); ++ AuDebugOn(xi->xi_nondir.array[idx] != h_ino); ++ xi->xi_nondir.array[idx] = 0; ++ spin_unlock(&xi->xi_nondir.spin); ++ wake_up_all(&xi->xi_nondir.wqh); ++} ++ ++int au_xinondir_enter(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ int *idx) ++{ ++ int err, found, empty; ++ struct au_xino *xi; ++ ++ err = 0; ++ *idx = -1; ++ if (!au_opt_test(au_mntflags(sb), XINO)) ++ goto out; /* no xino */ ++ ++ xi = au_sbr(sb, bindex)->br_xino; ++ ++again: ++ spin_lock(&xi->xi_nondir.spin); ++ found = au_xinondir_find(xi, h_ino); ++ if (found == -1) { ++ empty = au_xinondir_find(xi, /*h_ino*/0); ++ if (empty == -1) { ++ empty = xi->xi_nondir.total; ++ err = au_xinondir_expand(xi); ++ if (unlikely(err)) ++ goto out_unlock; ++ } ++ xi->xi_nondir.array[empty] = h_ino; ++ *idx = empty; ++ } else { ++ spin_unlock(&xi->xi_nondir.spin); ++ wait_event(xi->xi_nondir.wqh, ++ xi->xi_nondir.array[found] != h_ino); ++ goto again; ++ } ++ ++out_unlock: ++ spin_unlock(&xi->xi_nondir.spin); ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_xino_path(struct seq_file *seq, struct file *file) ++{ ++ int err; ++ ++ err = au_seq_path(seq, &file->f_path); ++ if (unlikely(err)) ++ goto out; ++ ++#define Deleted "\\040(deleted)" ++ seq->count -= sizeof(Deleted) - 1; ++ AuDebugOn(memcmp(seq->buf + seq->count, Deleted, ++ sizeof(Deleted) - 1)); ++#undef Deleted ++ ++out: ++ return err; ++} +diff -Naur null/include/uapi/linux/aufs_type.h linux-5.15.36/include/uapi/linux/aufs_type.h +--- /dev/null ++++ linux-5.15.36/include/uapi/linux/aufs_type.h 2022-05-10 16:51:39.879744219 +0300 +@@ -0,0 +1,452 @@ ++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++#ifndef __AUFS_TYPE_H__ ++#define __AUFS_TYPE_H__ ++ ++#define AUFS_NAME "aufs" ++ ++#ifdef __KERNEL__ ++/* ++ * define it before including all other headers. ++ * sched.h may use pr_* macros before defining "current", so define the ++ * no-current version first, and re-define later. ++ */ ++#define pr_fmt(fmt) AUFS_NAME " %s:%d: " fmt, __func__, __LINE__ ++#include ++#undef pr_fmt ++#define pr_fmt(fmt) \ ++ AUFS_NAME " %s:%d:%.*s[%d]: " fmt, __func__, __LINE__, \ ++ (int)sizeof(current->comm), current->comm, current->pid ++#include ++#else ++#include ++#include ++#include ++#endif /* __KERNEL__ */ ++ ++#define AUFS_VERSION "5.15.36-20220509" ++ ++/* todo? move this to linux-2.6.19/include/magic.h */ ++#define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's') ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef __KERNEL__ ++#ifdef CONFIG_AUFS_BRANCH_MAX_127 ++typedef int8_t aufs_bindex_t; ++#define AUFS_BRANCH_MAX 127 ++#else ++typedef int16_t aufs_bindex_t; ++#ifdef CONFIG_AUFS_BRANCH_MAX_511 ++#define AUFS_BRANCH_MAX 511 ++#elif defined(CONFIG_AUFS_BRANCH_MAX_1023) ++#define AUFS_BRANCH_MAX 1023 ++#elif defined(CONFIG_AUFS_BRANCH_MAX_32767) ++#define AUFS_BRANCH_MAX 32767 ++#endif ++#endif ++ ++#ifndef AUFS_BRANCH_MAX ++#error unknown CONFIG_AUFS_BRANCH_MAX value ++#endif ++#endif /* __KERNEL__ */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define AUFS_FSTYPE AUFS_NAME ++ ++#define AUFS_ROOT_INO 2 ++#define AUFS_FIRST_INO 11 ++ ++#define AUFS_WH_PFX ".wh." ++#define AUFS_WH_PFX_LEN ((int)sizeof(AUFS_WH_PFX) - 1) ++#define AUFS_WH_TMP_LEN 4 ++/* a limit for rmdir/rename a dir and copyup */ ++#define AUFS_MAX_NAMELEN (NAME_MAX \ ++ - AUFS_WH_PFX_LEN * 2 /* doubly whiteouted */\ ++ - 1 /* dot */\ ++ - AUFS_WH_TMP_LEN) /* hex */ ++#define AUFS_XINO_FNAME "." AUFS_NAME ".xino" ++#define AUFS_XINO_DEFPATH "/tmp/" AUFS_XINO_FNAME ++#define AUFS_XINO_DEF_SEC 30 /* seconds */ ++#define AUFS_XINO_DEF_TRUNC 45 /* percentage */ ++#define AUFS_DIRWH_DEF 3 ++#define AUFS_RDCACHE_DEF 10 /* seconds */ ++#define AUFS_RDCACHE_MAX 3600 /* seconds */ ++#define AUFS_RDBLK_DEF 512 /* bytes */ ++#define AUFS_RDHASH_DEF 32 ++#define AUFS_WKQ_NAME AUFS_NAME "d" ++#define AUFS_MFS_DEF_SEC 30 /* seconds */ ++#define AUFS_MFS_MAX_SEC 3600 /* seconds */ ++#define AUFS_FHSM_CACHE_DEF_SEC 30 /* seconds */ ++#define AUFS_PLINK_WARN 50 /* number of plinks in a single bucket */ ++ ++/* pseudo-link maintenace under /proc */ ++#define AUFS_PLINK_MAINT_NAME "plink_maint" ++#define AUFS_PLINK_MAINT_DIR "fs/" AUFS_NAME ++#define AUFS_PLINK_MAINT_PATH AUFS_PLINK_MAINT_DIR "/" AUFS_PLINK_MAINT_NAME ++ ++/* dirren, renamed dir */ ++#define AUFS_DR_INFO_PFX AUFS_WH_PFX ".dr." ++#define AUFS_DR_BRHINO_NAME AUFS_WH_PFX "hino" ++/* whiteouted doubly */ ++#define AUFS_WH_DR_INFO_PFX AUFS_WH_PFX AUFS_DR_INFO_PFX ++#define AUFS_WH_DR_BRHINO AUFS_WH_PFX AUFS_DR_BRHINO_NAME ++ ++#define AUFS_DIROPQ_NAME AUFS_WH_PFX ".opq" /* whiteouted doubly */ ++#define AUFS_WH_DIROPQ AUFS_WH_PFX AUFS_DIROPQ_NAME ++ ++#define AUFS_BASE_NAME AUFS_WH_PFX AUFS_NAME ++#define AUFS_PLINKDIR_NAME AUFS_WH_PFX "plnk" ++#define AUFS_ORPHDIR_NAME AUFS_WH_PFX "orph" ++ ++/* doubly whiteouted */ ++#define AUFS_WH_BASE AUFS_WH_PFX AUFS_BASE_NAME ++#define AUFS_WH_PLINKDIR AUFS_WH_PFX AUFS_PLINKDIR_NAME ++#define AUFS_WH_ORPHDIR AUFS_WH_PFX AUFS_ORPHDIR_NAME ++ ++/* branch permissions and attributes */ ++#define AUFS_BRPERM_RW "rw" ++#define AUFS_BRPERM_RO "ro" ++#define AUFS_BRPERM_RR "rr" ++#define AUFS_BRATTR_COO_REG "coo_reg" ++#define AUFS_BRATTR_COO_ALL "coo_all" ++#define AUFS_BRATTR_FHSM "fhsm" ++#define AUFS_BRATTR_UNPIN "unpin" ++#define AUFS_BRATTR_ICEX "icex" ++#define AUFS_BRATTR_ICEX_SEC "icexsec" ++#define AUFS_BRATTR_ICEX_SYS "icexsys" ++#define AUFS_BRATTR_ICEX_TR "icextr" ++#define AUFS_BRATTR_ICEX_USR "icexusr" ++#define AUFS_BRATTR_ICEX_OTH "icexoth" ++#define AUFS_BRRATTR_WH "wh" ++#define AUFS_BRWATTR_NLWH "nolwh" ++#define AUFS_BRWATTR_MOO "moo" ++ ++#define AuBrPerm_RW 1 /* writable, hardlinkable wh */ ++#define AuBrPerm_RO (1 << 1) /* readonly */ ++#define AuBrPerm_RR (1 << 2) /* natively readonly */ ++#define AuBrPerm_Mask (AuBrPerm_RW | AuBrPerm_RO | AuBrPerm_RR) ++ ++#define AuBrAttr_COO_REG (1 << 3) /* copy-up on open */ ++#define AuBrAttr_COO_ALL (1 << 4) ++#define AuBrAttr_COO_Mask (AuBrAttr_COO_REG | AuBrAttr_COO_ALL) ++ ++#define AuBrAttr_FHSM (1 << 5) /* file-based hsm */ ++#define AuBrAttr_UNPIN (1 << 6) /* rename-able top dir of ++ branch. meaningless since ++ linux-3.18-rc1 */ ++ ++/* ignore error in copying XATTR */ ++#define AuBrAttr_ICEX_SEC (1 << 7) ++#define AuBrAttr_ICEX_SYS (1 << 8) ++#define AuBrAttr_ICEX_TR (1 << 9) ++#define AuBrAttr_ICEX_USR (1 << 10) ++#define AuBrAttr_ICEX_OTH (1 << 11) ++#define AuBrAttr_ICEX (AuBrAttr_ICEX_SEC \ ++ | AuBrAttr_ICEX_SYS \ ++ | AuBrAttr_ICEX_TR \ ++ | AuBrAttr_ICEX_USR \ ++ | AuBrAttr_ICEX_OTH) ++ ++#define AuBrRAttr_WH (1 << 12) /* whiteout-able */ ++#define AuBrRAttr_Mask AuBrRAttr_WH ++ ++#define AuBrWAttr_NoLinkWH (1 << 13) /* un-hardlinkable whiteouts */ ++#define AuBrWAttr_MOO (1 << 14) /* move-up on open */ ++#define AuBrWAttr_Mask (AuBrWAttr_NoLinkWH | AuBrWAttr_MOO) ++ ++#define AuBrAttr_CMOO_Mask (AuBrAttr_COO_Mask | AuBrWAttr_MOO) ++ ++/* #warning test userspace */ ++#ifdef __KERNEL__ ++#ifndef CONFIG_AUFS_FHSM ++#undef AuBrAttr_FHSM ++#define AuBrAttr_FHSM 0 ++#endif ++#ifndef CONFIG_AUFS_XATTR ++#undef AuBrAttr_ICEX ++#define AuBrAttr_ICEX 0 ++#undef AuBrAttr_ICEX_SEC ++#define AuBrAttr_ICEX_SEC 0 ++#undef AuBrAttr_ICEX_SYS ++#define AuBrAttr_ICEX_SYS 0 ++#undef AuBrAttr_ICEX_TR ++#define AuBrAttr_ICEX_TR 0 ++#undef AuBrAttr_ICEX_USR ++#define AuBrAttr_ICEX_USR 0 ++#undef AuBrAttr_ICEX_OTH ++#define AuBrAttr_ICEX_OTH 0 ++#endif ++#endif ++ ++/* the longest combination */ ++/* AUFS_BRATTR_ICEX and AUFS_BRATTR_ICEX_TR don't affect here */ ++#define AuBrPermStrSz sizeof(AUFS_BRPERM_RW \ ++ "+" AUFS_BRATTR_COO_REG \ ++ "+" AUFS_BRATTR_FHSM \ ++ "+" AUFS_BRATTR_UNPIN \ ++ "+" AUFS_BRATTR_ICEX_SEC \ ++ "+" AUFS_BRATTR_ICEX_SYS \ ++ "+" AUFS_BRATTR_ICEX_USR \ ++ "+" AUFS_BRATTR_ICEX_OTH \ ++ "+" AUFS_BRWATTR_NLWH) ++ ++typedef struct { ++ char a[AuBrPermStrSz]; ++} au_br_perm_str_t; ++ ++static inline int au_br_writable(int brperm) ++{ ++ return brperm & AuBrPerm_RW; ++} ++ ++static inline int au_br_whable(int brperm) ++{ ++ return brperm & (AuBrPerm_RW | AuBrRAttr_WH); ++} ++ ++static inline int au_br_wh_linkable(int brperm) ++{ ++ return !(brperm & AuBrWAttr_NoLinkWH); ++} ++ ++static inline int au_br_cmoo(int brperm) ++{ ++ return brperm & AuBrAttr_CMOO_Mask; ++} ++ ++static inline int au_br_fhsm(int brperm) ++{ ++ return brperm & AuBrAttr_FHSM; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ioctl */ ++enum { ++ /* readdir in userspace */ ++ AuCtl_RDU, ++ AuCtl_RDU_INO, ++ ++ AuCtl_WBR_FD, /* pathconf wrapper */ ++ AuCtl_IBUSY, /* busy inode */ ++ AuCtl_MVDOWN, /* move-down */ ++ AuCtl_BR, /* info about branches */ ++ AuCtl_FHSM_FD /* connection for fhsm */ ++}; ++ ++/* borrowed from linux/include/linux/kernel.h */ ++#ifndef ALIGN ++#ifdef _GNU_SOURCE ++#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1) ++#else ++#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) ++#endif ++#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask)) ++#endif ++ ++/* borrowed from linux/include/linux/compiler-gcc3.h */ ++#ifndef __aligned ++#define __aligned(x) __attribute__((aligned(x))) ++#endif ++ ++#ifdef __KERNEL__ ++#ifndef __packed ++#define __packed __attribute__((packed)) ++#endif ++#endif ++ ++struct au_rdu_cookie { ++ uint64_t h_pos; ++ int16_t bindex; ++ uint8_t flags; ++ uint8_t pad; ++ uint32_t generation; ++} __aligned(8); ++ ++struct au_rdu_ent { ++ uint64_t ino; ++ int16_t bindex; ++ uint8_t type; ++ uint8_t nlen; ++ uint8_t wh; ++ char name[]; ++} __aligned(8); ++ ++static inline int au_rdu_len(int nlen) ++{ ++ /* include the terminating NULL */ ++ return ALIGN(sizeof(struct au_rdu_ent) + nlen + 1, ++ sizeof(uint64_t)); ++} ++ ++union au_rdu_ent_ul { ++ struct au_rdu_ent __user *e; ++ uint64_t ul; ++}; ++ ++enum { ++ AufsCtlRduV_SZ, ++ AufsCtlRduV_End ++}; ++ ++struct aufs_rdu { ++ /* input */ ++ union { ++ uint64_t sz; /* AuCtl_RDU */ ++ uint64_t nent; /* AuCtl_RDU_INO */ ++ }; ++ union au_rdu_ent_ul ent; ++ uint16_t verify[AufsCtlRduV_End]; ++ ++ /* input/output */ ++ uint32_t blk; ++ ++ /* output */ ++ union au_rdu_ent_ul tail; ++ /* number of entries which were added in a single call */ ++ uint64_t rent; ++ uint8_t full; ++ uint8_t shwh; ++ ++ struct au_rdu_cookie cookie; ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dirren. the branch is identified by the filename who contains this */ ++struct au_drinfo { ++ uint64_t ino; ++ union { ++ uint8_t oldnamelen; ++ uint64_t _padding; ++ }; ++ uint8_t oldname[]; ++} __aligned(8); ++ ++struct au_drinfo_fdata { ++ uint32_t magic; ++ struct au_drinfo drinfo; ++} __aligned(8); ++ ++#define AUFS_DRINFO_MAGIC_V1 ('a' << 24 | 'd' << 16 | 'r' << 8 | 0x01) ++/* future */ ++#define AUFS_DRINFO_MAGIC_V2 ('a' << 24 | 'd' << 16 | 'r' << 8 | 0x02) ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct aufs_wbr_fd { ++ uint32_t oflags; ++ int16_t brid; ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct aufs_ibusy { ++ uint64_t ino, h_ino; ++ int16_t bindex; ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* error code for move-down */ ++/* the actual message strings are implemented in aufs-util.git */ ++enum { ++ EAU_MVDOWN_OPAQUE = 1, ++ EAU_MVDOWN_WHITEOUT, ++ EAU_MVDOWN_UPPER, ++ EAU_MVDOWN_BOTTOM, ++ EAU_MVDOWN_NOUPPER, ++ EAU_MVDOWN_NOLOWERBR, ++ EAU_Last ++}; ++ ++/* flags for move-down */ ++#define AUFS_MVDOWN_DMSG 1 ++#define AUFS_MVDOWN_OWLOWER (1 << 1) /* overwrite lower */ ++#define AUFS_MVDOWN_KUPPER (1 << 2) /* keep upper */ ++#define AUFS_MVDOWN_ROLOWER (1 << 3) /* do even if lower is RO */ ++#define AUFS_MVDOWN_ROLOWER_R (1 << 4) /* did on lower RO */ ++#define AUFS_MVDOWN_ROUPPER (1 << 5) /* do even if upper is RO */ ++#define AUFS_MVDOWN_ROUPPER_R (1 << 6) /* did on upper RO */ ++#define AUFS_MVDOWN_BRID_UPPER (1 << 7) /* upper brid */ ++#define AUFS_MVDOWN_BRID_LOWER (1 << 8) /* lower brid */ ++#define AUFS_MVDOWN_FHSM_LOWER (1 << 9) /* find fhsm attr for lower */ ++#define AUFS_MVDOWN_STFS (1 << 10) /* req. stfs */ ++#define AUFS_MVDOWN_STFS_FAILED (1 << 11) /* output: stfs is unusable */ ++#define AUFS_MVDOWN_BOTTOM (1 << 12) /* output: no more lowers */ ++ ++/* index for move-down */ ++enum { ++ AUFS_MVDOWN_UPPER, ++ AUFS_MVDOWN_LOWER, ++ AUFS_MVDOWN_NARRAY ++}; ++ ++/* ++ * additional info of move-down ++ * number of free blocks and inodes. ++ * subset of struct kstatfs, but smaller and always 64bit. ++ */ ++struct aufs_stfs { ++ uint64_t f_blocks; ++ uint64_t f_bavail; ++ uint64_t f_files; ++ uint64_t f_ffree; ++}; ++ ++struct aufs_stbr { ++ int16_t brid; /* optional input */ ++ int16_t bindex; /* output */ ++ struct aufs_stfs stfs; /* output when AUFS_MVDOWN_STFS set */ ++} __aligned(8); ++ ++struct aufs_mvdown { ++ uint32_t flags; /* input/output */ ++ struct aufs_stbr stbr[AUFS_MVDOWN_NARRAY]; /* input/output */ ++ int8_t au_errno; /* output */ ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++union aufs_brinfo { ++ /* PATH_MAX may differ between kernel-space and user-space */ ++ char _spacer[4096]; ++ struct { ++ int16_t id; ++ int perm; ++ char path[]; ++ }; ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define AuCtlType 'A' ++#define AUFS_CTL_RDU _IOWR(AuCtlType, AuCtl_RDU, struct aufs_rdu) ++#define AUFS_CTL_RDU_INO _IOWR(AuCtlType, AuCtl_RDU_INO, struct aufs_rdu) ++#define AUFS_CTL_WBR_FD _IOW(AuCtlType, AuCtl_WBR_FD, \ ++ struct aufs_wbr_fd) ++#define AUFS_CTL_IBUSY _IOWR(AuCtlType, AuCtl_IBUSY, struct aufs_ibusy) ++#define AUFS_CTL_MVDOWN _IOWR(AuCtlType, AuCtl_MVDOWN, \ ++ struct aufs_mvdown) ++#define AUFS_CTL_BRINFO _IOW(AuCtlType, AuCtl_BR, union aufs_brinfo) ++#define AUFS_CTL_FHSM_FD _IOW(AuCtlType, AuCtl_FHSM_FD, int) ++ ++#endif /* __AUFS_TYPE_H__ */ diff --git a/kernel/tools/perf/files/patches/aufs5/tmpfs-idr.patch b/kernel/tools/perf/files/patches/aufs5/tmpfs-idr.patch new file mode 100644 index 0000000000..be89bbeeaa --- /dev/null +++ b/kernel/tools/perf/files/patches/aufs5/tmpfs-idr.patch @@ -0,0 +1,221 @@ +SPDX-License-Identifier: GPL-2.0 + +diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h +index 166158b6e917..0e9606171432 100644 +--- a/include/linux/shmem_fs.h ++++ b/include/linux/shmem_fs.h +@@ -28,10 +28,13 @@ struct shmem_inode_info { + }; + + struct shmem_sb_info { ++ struct mutex idr_lock; ++ bool idr_nouse; ++ struct idr idr; /* manages inode-number */ + unsigned long max_blocks; /* How many blocks are allowed */ + struct percpu_counter used_blocks; /* How many are allocated */ +- unsigned long max_inodes; /* How many inodes are allowed */ +- unsigned long free_inodes; /* How many are left for allocation */ ++ int max_inodes; /* How many inodes are allowed */ ++ int free_inodes; /* How many are left for allocation */ + raw_spinlock_t stat_lock; /* Serialize shmem_sb_info changes */ + umode_t mode; /* Mount mode for root directory */ + unsigned char huge; /* Whether to try for hugepages */ +diff --git a/mm/shmem.c b/mm/shmem.c +index 1609a8daba26..b3e5f52a5aa2 100644 +--- a/mm/shmem.c ++++ b/mm/shmem.c +@@ -108,7 +108,7 @@ struct shmem_falloc { + + struct shmem_options { + unsigned long long blocks; +- unsigned long long inodes; ++ int inodes; + struct mempolicy *mpol; + kuid_t uid; + kgid_t gid; +@@ -128,11 +128,14 @@ static unsigned long shmem_default_max_blocks(void) + return totalram_pages() / 2; + } + +-static unsigned long shmem_default_max_inodes(void) ++static int shmem_default_max_inodes(void) + { + unsigned long nr_pages = totalram_pages(); ++ unsigned long ul; + +- return min(nr_pages - totalhigh_pages(), nr_pages / 2); ++ ul = INT_MAX; ++ ul = min3(ul, nr_pages - totalhigh_pages(), nr_pages / 2); ++ return ul; + } + #endif + +@@ -1165,6 +1168,11 @@ static void shmem_evict_inode(struct inode *inode) + + simple_xattrs_free(&info->xattrs); + WARN_ON(inode->i_blocks); ++ if (!sbinfo->idr_nouse && inode->i_ino) { ++ mutex_lock(&sbinfo->idr_lock); ++ idr_remove(&sbinfo->idr, inode->i_ino); ++ mutex_unlock(&sbinfo->idr_lock); ++ } + shmem_free_inode(inode->i_sb); + clear_inode(inode); + } +@@ -2336,6 +2344,25 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode + break; + } + ++ if (!sbinfo->idr_nouse) { ++ /* inum 0 and 1 are unused */ ++ mutex_lock(&sbinfo->idr_lock); ++ ino = idr_alloc(&sbinfo->idr, inode, 2, INT_MAX, ++ GFP_NOFS); ++ if (ino > 0) { ++ inode->i_ino = ino; ++ mutex_unlock(&sbinfo->idr_lock); ++ __insert_inode_hash(inode, inode->i_ino); ++ } else { ++ inode->i_ino = 0; ++ mutex_unlock(&sbinfo->idr_lock); ++ iput(inode); ++ /* shmem_free_inode() will be called */ ++ inode = NULL; ++ } ++ } else ++ inode->i_ino = ino; ++ + lockdep_annotate_inode_mutex_key(inode); + } else + shmem_free_inode(sb); +@@ -3250,8 +3277,7 @@ static struct dentry *shmem_get_parent(struct dentry *child) + static int shmem_match(struct inode *ino, void *vfh) + { + __u32 *fh = vfh; +- __u64 inum = fh[2]; +- inum = (inum << 32) | fh[1]; ++ __u64 inum = fh[1]; + return ino->i_ino == inum && fh[0] == ino->i_generation; + } + +@@ -3271,14 +3297,11 @@ static struct dentry *shmem_fh_to_dentry(struct super_block *sb, + struct dentry *dentry = NULL; + u64 inum; + +- if (fh_len < 3) ++ if (fh_len < 2) + return NULL; + +- inum = fid->raw[2]; +- inum = (inum << 32) | fid->raw[1]; +- +- inode = ilookup5(sb, (unsigned long)(inum + fid->raw[0]), +- shmem_match, fid->raw); ++ inum = fid->raw[1]; ++ inode = ilookup5(sb, inum, shmem_match, fid->raw); + if (inode) { + dentry = shmem_find_alias(inode); + iput(inode); +@@ -3290,30 +3313,15 @@ static struct dentry *shmem_fh_to_dentry(struct super_block *sb, + static int shmem_encode_fh(struct inode *inode, __u32 *fh, int *len, + struct inode *parent) + { +- if (*len < 3) { +- *len = 3; ++ if (*len < 2) { ++ *len = 2; + return FILEID_INVALID; + } + +- if (inode_unhashed(inode)) { +- /* Unfortunately insert_inode_hash is not idempotent, +- * so as we hash inodes here rather than at creation +- * time, we need a lock to ensure we only try +- * to do it once +- */ +- static DEFINE_SPINLOCK(lock); +- spin_lock(&lock); +- if (inode_unhashed(inode)) +- __insert_inode_hash(inode, +- inode->i_ino + inode->i_generation); +- spin_unlock(&lock); +- } +- + fh[0] = inode->i_generation; + fh[1] = inode->i_ino; +- fh[2] = ((__u64)inode->i_ino) >> 32; + +- *len = 3; ++ *len = 2; + return 1; + } + +@@ -3392,7 +3400,7 @@ static int shmem_parse_one(struct fs_context *fc, struct fs_parameter *param) + break; + case Opt_nr_inodes: + ctx->inodes = memparse(param->string, &rest); +- if (*rest) ++ if (*rest || ctx->inodes < 2) + goto bad_value; + ctx->seen |= SHMEM_SEEN_INODES; + break; +@@ -3502,7 +3510,7 @@ static int shmem_reconfigure(struct fs_context *fc) + { + struct shmem_options *ctx = fc->fs_private; + struct shmem_sb_info *sbinfo = SHMEM_SB(fc->root->d_sb); +- unsigned long inodes; ++ int inodes; + struct mempolicy *mpol = NULL; + const char *err; + +@@ -3571,7 +3579,7 @@ static int shmem_show_options(struct seq_file *seq, struct dentry *root) + seq_printf(seq, ",size=%luk", + sbinfo->max_blocks << (PAGE_SHIFT - 10)); + if (sbinfo->max_inodes != shmem_default_max_inodes()) +- seq_printf(seq, ",nr_inodes=%lu", sbinfo->max_inodes); ++ seq_printf(seq, ",nr_inodes=%d", sbinfo->max_inodes); + if (sbinfo->mode != (0777 | S_ISVTX)) + seq_printf(seq, ",mode=%03ho", sbinfo->mode); + if (!uid_eq(sbinfo->uid, GLOBAL_ROOT_UID)) +@@ -3618,6 +3626,8 @@ static void shmem_put_super(struct super_block *sb) + { + struct shmem_sb_info *sbinfo = SHMEM_SB(sb); + ++ if (!sbinfo->idr_nouse) ++ idr_destroy(&sbinfo->idr); + free_percpu(sbinfo->ino_batch); + percpu_counter_destroy(&sbinfo->used_blocks); + mpol_put(sbinfo->mpol); +@@ -3660,6 +3670,8 @@ static int shmem_fill_super(struct super_block *sb, struct fs_context *fc) + #else + sb->s_flags |= SB_NOUSER; + #endif ++ mutex_init(&sbinfo->idr_lock); ++ idr_init(&sbinfo->idr); + sbinfo->max_blocks = ctx->blocks; + sbinfo->free_inodes = sbinfo->max_inodes = ctx->inodes; + if (sb->s_flags & SB_KERNMOUNT) { +@@ -3777,6 +3789,15 @@ static void shmem_destroy_inodecache(void) + kmem_cache_destroy(shmem_inode_cachep); + } + ++static __init void shmem_no_idr(struct super_block *sb) ++{ ++ struct shmem_sb_info *sbinfo; ++ ++ sbinfo = SHMEM_SB(sb); ++ sbinfo->idr_nouse = true; ++ idr_destroy(&sbinfo->idr); ++} ++ + const struct address_space_operations shmem_aops = { + .writepage = shmem_writepage, + .set_page_dirty = __set_page_dirty_no_writeback, +@@ -3918,6 +3939,7 @@ int __init shmem_init(void) + pr_err("Could not kern_mount tmpfs\n"); + goto out1; + } ++ shmem_no_idr(shm_mnt->mnt_sb); + + #ifdef CONFIG_TRANSPARENT_HUGEPAGE + if (has_transparent_hugepage() && shmem_huge > SHMEM_HUGE_DENY) diff --git a/kernel/tools/perf/files/patches/aufs5/vfs-ino.patch b/kernel/tools/perf/files/patches/aufs5/vfs-ino.patch new file mode 100644 index 0000000000..992d86c106 --- /dev/null +++ b/kernel/tools/perf/files/patches/aufs5/vfs-ino.patch @@ -0,0 +1,24 @@ +SPDX-License-Identifier: GPL-2.0 + +diff --git a/fs/inode.c b/fs/inode.c +index 9abc88d7959c..82b13641423c 100644 +--- a/fs/inode.c ++++ b/fs/inode.c +@@ -904,6 +904,8 @@ unsigned int get_next_ino(void) + unsigned int *p = &get_cpu_var(last_ino); + unsigned int res = *p; + ++start: ++ + #ifdef CONFIG_SMP + if (unlikely((res & (LAST_INO_BATCH-1)) == 0)) { + static atomic_t shared_last_ino; +@@ -916,7 +918,7 @@ unsigned int get_next_ino(void) + res++; + /* get_next_ino should not provide a 0 inode number */ + if (unlikely(!res)) +- res++; ++ goto start; + *p = res; + put_cpu_var(last_ino); + return res; diff --git a/kernel/tools/perf/files/patches/linux/patch-5.10.15.xz b/kernel/tools/perf/files/patches/linux/patch-5.10.15.xz deleted file mode 100644 index 42cda9d802..0000000000 Binary files a/kernel/tools/perf/files/patches/linux/patch-5.10.15.xz and /dev/null differ diff --git a/kernel/tools/perf/files/patches/linux/patch-5.10.19.xz b/kernel/tools/perf/files/patches/linux/patch-5.10.19.xz deleted file mode 100644 index 26b2fcba4b..0000000000 Binary files a/kernel/tools/perf/files/patches/linux/patch-5.10.19.xz and /dev/null differ diff --git a/kernel/tools/perf/files/patches/linux/patch-5.10.41.xz b/kernel/tools/perf/files/patches/linux/patch-5.10.41.xz deleted file mode 100644 index 57ece77117..0000000000 Binary files a/kernel/tools/perf/files/patches/linux/patch-5.10.41.xz and /dev/null differ diff --git a/kernel/tools/perf/files/patches/linux/patch-5.10.45.xz b/kernel/tools/perf/files/patches/linux/patch-5.10.45.xz deleted file mode 100644 index 27c5dd0c67..0000000000 Binary files a/kernel/tools/perf/files/patches/linux/patch-5.10.45.xz and /dev/null differ diff --git a/kernel/tools/perf/files/patches/linux/patch-5.15.41.xz b/kernel/tools/perf/files/patches/linux/patch-5.15.41.xz new file mode 100644 index 0000000000..3de4fc5db1 Binary files /dev/null and b/kernel/tools/perf/files/patches/linux/patch-5.15.41.xz differ diff --git a/kernel/tools/perf/files/patches/mageia/3rd-3rdparty-merge.patch b/kernel/tools/perf/files/patches/mageia/3rd-3rdparty-merge.patch index 1bae65c085..78d502ec1d 100644 --- a/kernel/tools/perf/files/patches/mageia/3rd-3rdparty-merge.patch +++ b/kernel/tools/perf/files/patches/mageia/3rd-3rdparty-merge.patch @@ -16,38 +16,42 @@ Signed-off-by: Thomas Backlund arch/x86/Kconfig | 2 ++ 4 files changed, 7 insertions(+), 1 deletion(-) ---- linux-5.8/arch/arm64/Kconfig.orig 2020-08-05 16:08:02.466740952 +0200 -+++ linux-5.8/arch/arm64/Kconfig 2020-08-05 16:08:13.368741815 +0200 -@@ -1910,3 +1910,5 @@ source "arch/arm64/kvm/Kconfig" - if CRYPTO - source "arch/arm64/crypto/Kconfig" - endif -+ -+source "3rdparty/Kconfig" ---- linux-5.8/Makefile.orig 2020-08-05 16:09:32.265748061 +0200 -+++ linux-5.8/Makefile 2020-08-05 16:10:02.553750458 +0200 -@@ -651,7 +651,7 @@ endif - ifeq ($(KBUILD_EXTMOD),) - # Objects we will link into vmlinux / subdirs we need to visit - core-y := init/ usr/ --drivers-y := drivers/ sound/ -+drivers-y := drivers/ sound/ 3rdparty/ - drivers-$(CONFIG_SAMPLES) += samples/ - drivers-y += net/ virt/ - libs-y := lib/ ---- linux-5.8/arch/x86/Kconfig.orig 2020-08-05 16:10:48.805754119 +0200 -+++ linux-5.8/arch/x86/Kconfig 2020-08-05 16:11:04.602755370 +0200 -@@ -2913,3 +2913,5 @@ source "drivers/firmware/Kconfig" - source "arch/x86/kvm/Kconfig" - - source "arch/x86/Kconfig.assembler" -+ -+source "3rdparty/Kconfig" ---- linux-5.8/arch/arm/Kconfig.orig 2020-08-05 16:12:08.314760413 +0200 -+++ linux-5.8/arch/arm/Kconfig 2020-08-05 16:12:22.786761559 +0200 -@@ -2064,3 +2064,5 @@ source "arch/arm/crypto/Kconfig" +diff -Nurp linux-5.12/arch/arm/Kconfig linux-5.12-3rd/arch/arm/Kconfig +--- linux-5.12/arch/arm/Kconfig 2021-04-25 23:49:08.000000000 +0300 ++++ linux-5.12-3rd/arch/arm/Kconfig 2021-04-26 18:10:06.513775304 +0300 +@@ -2016,3 +2016,5 @@ source "arch/arm/crypto/Kconfig" endif source "arch/arm/Kconfig.assembler" + +source "3rdparty/Kconfig" +diff -Nurp linux-5.12/arch/arm64/Kconfig linux-5.12-3rd/arch/arm64/Kconfig +--- linux-5.12/arch/arm64/Kconfig 2021-04-25 23:49:08.000000000 +0300 ++++ linux-5.12-3rd/arch/arm64/Kconfig 2021-04-26 18:10:06.512775257 +0300 +@@ -1959,3 +1959,5 @@ source "arch/arm64/kvm/Kconfig" + if CRYPTO + source "arch/arm64/crypto/Kconfig" + endif ++ ++source "3rdparty/Kconfig" +diff -Nurp linux-5.12/arch/x86/Kconfig linux-5.12-3rd/arch/x86/Kconfig +--- linux-5.12/arch/x86/Kconfig 2021-04-25 23:49:08.000000000 +0300 ++++ linux-5.12-3rd/arch/x86/Kconfig 2021-04-26 18:10:06.512775257 +0300 +@@ -2909,3 +2909,5 @@ source "drivers/firmware/Kconfig" + source "arch/x86/kvm/Kconfig" + + source "arch/x86/Kconfig.assembler" ++ ++source "3rdparty/Kconfig" +diff -Nurp linux-5.14/Makefile linux-5.14-3rd/Makefile +--- linux-5.14/Makefile ++++ linux-5.14-3rd/Makefile +@@ -670,7 +670,7 @@ endif + ifeq ($(KBUILD_EXTMOD),) + # Objects we will link into vmlinux / subdirs we need to visit + core-y := init/ usr/ arch/$(SRCARCH)/ +-drivers-y := drivers/ sound/ ++drivers-y := drivers/ sound/ 3rdparty/ + drivers-$(CONFIG_SAMPLES) += samples/ + drivers-$(CONFIG_NET) += net/ + drivers-y += virt/ diff --git a/kernel/tools/perf/files/patches/mageia/3rd-fix-kconfig.patch b/kernel/tools/perf/files/patches/mageia/3rd-fix-kconfig.patch index 6d1a440604..783807d71e 100644 --- a/kernel/tools/perf/files/patches/mageia/3rd-fix-kconfig.patch +++ b/kernel/tools/perf/files/patches/mageia/3rd-fix-kconfig.patch @@ -9,17 +9,6 @@ diff -up ./3rdparty/rtl8723de/Kconfig.tv ./3rdparty/rtl8723de/Kconfig + help Help message of RTL8723DE -diff -up ./3rdparty/rtl8812au/Kconfig.tv ./3rdparty/rtl8812au/Kconfig ---- ./3rdparty/rtl8812au/Kconfig.tv 2020-10-13 21:02:36.391016614 +0200 -+++ ./3rdparty/rtl8812au/Kconfig 2020-10-13 20:59:07.421226249 +0200 -@@ -1,6 +1,6 @@ - config RTL8812AU - tristate "Realtek 8812au USB WiFi" - depends on USB -- ---help--- -+ help - Help message of 8812au - diff -up ./3rdparty/rtl8821ce/Kconfig.tv ./3rdparty/rtl8821ce/Kconfig --- ./3rdparty/rtl8821ce/Kconfig.tv 2020-10-13 16:09:11.157856145 +0200 +++ ./3rdparty/rtl8821ce/Kconfig 2020-10-13 20:58:17.242118685 +0200 diff --git a/kernel/tools/perf/files/patches/mageia/3rd-rtl8812au-kernel-5.12.patch b/kernel/tools/perf/files/patches/mageia/3rd-rtl8812au-kernel-5.12.patch new file mode 100644 index 0000000000..c53561cf98 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/3rd-rtl8812au-kernel-5.12.patch @@ -0,0 +1,12 @@ +diff -urp linux/3rdparty/rtl8812au.orig/os_dep/linux/recv_linux.c linux/3rdparty/rtl8812au/os_dep/linux/recv_linux.c +--- linux/3rdparty/rtl8812au.orig/os_dep/linux/recv_linux.c 2021-04-26 18:35:37.411027594 +0300 ++++ linux/3rdparty/rtl8812au/os_dep/linux/recv_linux.c 2021-04-26 18:53:13.502814526 +0300 +@@ -353,7 +353,7 @@ static int napi_recv(_adapter *padapter, + + rx_ok = _FALSE; + +-#ifdef CONFIG_RTW_GRO ++#if defined(CONFIG_RTW_GRO) && LINUX_VERSION_CODE < KERNEL_VERSION(5, 12, 0) + if (pregistrypriv->en_gro) { + if (rtw_napi_gro_receive(&padapter->napi, pskb) != GRO_DROP) + rx_ok = _TRUE; diff --git a/kernel/tools/perf/files/patches/mageia/3rd-rtl8812au-kernel-5.15.patch b/kernel/tools/perf/files/patches/mageia/3rd-rtl8812au-kernel-5.15.patch new file mode 100644 index 0000000000..86a002fe3b --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/3rd-rtl8812au-kernel-5.15.patch @@ -0,0 +1,66 @@ + +From: +https://github.com/aircrack-ng/rtl8812au/commit/47a38b7c736dd9e9baac9eb07a6dceb83429fb49 + +diff -Nurp linux-5.15/3rdparty/rtl8812au.orig/core/rtw_br_ext.c linux-5.15/3rdparty/rtl8812au/core/rtw_br_ext.c +--- linux-5.15/3rdparty/rtl8812au.orig/core/rtw_br_ext.c 2021-11-08 23:40:48.236272741 +0200 ++++ linux-5.15/3rdparty/rtl8812au/core/rtw_br_ext.c 2021-11-08 23:49:12.118046953 +0200 +@@ -17,7 +17,10 @@ + #ifdef __KERNEL__ + #include + #include ++ #include ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0) + #include ++#endif + #include + #include + #include +@@ -169,6 +172,7 @@ static __inline__ void __nat25_generate_ + } + + ++#ifdef _NET_INET_IPX_H_ + static __inline__ void __nat25_generate_ipx_network_addr_with_node(unsigned char *networkAddr, + unsigned int *ipxNetAddr, unsigned char *ipxNodeAddr) + { +@@ -189,6 +193,7 @@ static __inline__ void __nat25_generate_ + memcpy(networkAddr + 1, (unsigned char *)ipxNetAddr, 4); + memcpy(networkAddr + 5, (unsigned char *)ipxSocketAddr, 2); + } ++#endif + + + static __inline__ void __nat25_generate_apple_network_addr(unsigned char *networkAddr, +@@ -330,6 +335,7 @@ static __inline__ int __nat25_network_ha + x = networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10]; + + return x & (NAT25_HASH_SIZE - 1); ++#ifdef _NET_INET_IPX_H_ + } else if (networkAddr[0] == NAT25_IPX) { + unsigned long x; + +@@ -337,6 +343,7 @@ static __inline__ int __nat25_network_ha + networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10]; + + return x & (NAT25_HASH_SIZE - 1); ++#endif + } else if (networkAddr[0] == NAT25_APPLE) { + unsigned long x; + +@@ -889,6 +896,7 @@ int nat25_db_handle(_adapter *priv, stru + } + } + ++#ifdef _NET_INET_IPX_H_ + /*---------------------------------------------------*/ + /* Handle IPX and Apple Talk frame */ + /*---------------------------------------------------*/ +@@ -1109,6 +1117,7 @@ int nat25_db_handle(_adapter *priv, stru + + return -1; + } ++#endif + + /*---------------------------------------------------*/ + /* Handle PPPoE frame */ diff --git a/kernel/tools/perf/files/patches/mageia/3rd-rtl8812au-rename.patch b/kernel/tools/perf/files/patches/mageia/3rd-rtl8812au-rename.patch index a255a55886..bcf02987c2 100644 --- a/kernel/tools/perf/files/patches/mageia/3rd-rtl8812au-rename.patch +++ b/kernel/tools/perf/files/patches/mageia/3rd-rtl8812au-rename.patch @@ -4,15 +4,15 @@ Adjust driver bits so it keeps the name of the replaced driver Signed-off-by: Thomas Backlund --- - 3rdparty/rtl8812au/Kconfig | 6 +++--- + 3rdparty/rtl8812au/Kconfig | 7 +++---- 3rdparty/rtl8812au/Makefile | 8 ++++---- 3rdparty/rtl8812au/hal/hal_com.c | 2 +- 3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c | 2 +- - 4 files changed, 9 insertions(+), 9 deletions(-) + 4 files changed, 9 insertions(+), 10 deletions(-) -diff -Nurp linux-5.5/3rdparty/rtl8812au.orig/hal/hal_com.c linux-5.5/3rdparty/rtl8812au/hal/hal_com.c ---- linux-5.5/3rdparty/rtl8812au.orig/hal/hal_com.c 2020-03-09 01:46:04.750166543 +0200 -+++ linux-5.5/3rdparty/rtl8812au/hal/hal_com.c 2020-03-11 18:23:33.839805026 +0200 +diff -Nurp linux-5.11/3rdparty/rtl8812au.orig/hal/hal_com.c linux-5.11/3rdparty/rtl8812au/hal/hal_com.c +--- linux-5.11/3rdparty/rtl8812au.orig/hal/hal_com.c 2021-03-07 18:43:20.313672664 +0200 ++++ linux-5.11/3rdparty/rtl8812au/hal/hal_com.c 2021-03-07 18:43:51.392141299 +0200 @@ -12879,7 +12879,7 @@ bypass_hw_pg: _rtw_memset(hal_data->EEPROMMACAddr, 0, ETH_ALEN); ret = _FAIL; @@ -22,25 +22,25 @@ diff -Nurp linux-5.5/3rdparty/rtl8812au.orig/hal/hal_com.c linux-5.5/3rdparty/rt return ret; } -diff -Nurp linux-5.5/3rdparty/rtl8812au.orig/Kconfig linux-5.5/3rdparty/rtl8812au/Kconfig ---- linux-5.5/3rdparty/rtl8812au.orig/Kconfig 2020-03-09 01:46:04.682163430 +0200 -+++ linux-5.5/3rdparty/rtl8812au/Kconfig 2020-03-11 18:21:33.457357175 +0200 -@@ -1,6 +1,6 @@ +diff -Nurp linux-5.11/3rdparty/rtl8812au.orig/Kconfig linux-5.11/3rdparty/rtl8812au/Kconfig +--- linux-5.11/3rdparty/rtl8812au.orig/Kconfig 2021-03-07 18:43:20.369675309 +0200 ++++ linux-5.11/3rdparty/rtl8812au/Kconfig 2021-03-07 18:45:22.910465892 +0200 +@@ -1,6 +1,5 @@ -config 88XXAU - tristate "Realtek 88XXau USB WiFi" +config RTL8812AU + tristate "Realtek 8812au USB WiFi" depends on USB - ---help--- + help - Help message of 88XXau +- + Help message of 8812au +diff -Nurp linux-5.11/3rdparty/rtl8812au.orig/Makefile linux-5.11/3rdparty/rtl8812au/Makefile +--- linux-5.11/3rdparty/rtl8812au.orig/Makefile 2021-03-07 18:43:20.370675357 +0200 ++++ linux-5.11/3rdparty/rtl8812au/Makefile 2021-03-07 18:43:51.401141725 +0200 +@@ -180,9 +180,9 @@ endif -diff -Nurp linux-5.5/3rdparty/rtl8812au.orig/Makefile linux-5.5/3rdparty/rtl8812au/Makefile ---- linux-5.5/3rdparty/rtl8812au.orig/Makefile 2020-03-09 01:46:04.682163430 +0200 -+++ linux-5.5/3rdparty/rtl8812au/Makefile 2020-03-11 18:22:16.769317077 +0200 -@@ -179,9 +179,9 @@ endif - - ifeq ($(CONFIG_RTL8812A)_$(CONFIG_RTL8821A)_$(CONFIG_RTL8814A), y_y_y) + ifeq ($(CONFIG_RTL8812A)_$(CONFIG_RTL8821A)_$(CONFIG_RTL8814A), y_y_n) -EXTRA_CFLAGS += -DDRV_NAME=\"rtl88XXau\" +EXTRA_CFLAGS += -DDRV_NAME=\"rtl8812au\" @@ -50,7 +50,7 @@ diff -Nurp linux-5.5/3rdparty/rtl8812au.orig/Makefile linux-5.5/3rdparty/rtl8812 endif else EXTRA_CFLAGS += -DDRV_NAME=\"rtl8812au\" -@@ -2233,11 +2233,11 @@ $(MODULE_NAME)-y += $(_PLATFORM_FILES) +@@ -2232,11 +2232,11 @@ $(MODULE_NAME)-y += $(_PLATFORM_FILES) $(MODULE_NAME)-$(CONFIG_MP_INCLUDED) += core/rtw_mp.o @@ -64,10 +64,10 @@ diff -Nurp linux-5.5/3rdparty/rtl8812au.orig/Makefile linux-5.5/3rdparty/rtl8812 all: modules -diff -Nurp linux-5.5/3rdparty/rtl8812au.orig/os_dep/linux/ioctl_cfg80211.c linux-5.5/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c ---- linux-5.5/3rdparty/rtl8812au.orig/os_dep/linux/ioctl_cfg80211.c 2020-03-09 01:46:04.798168741 +0200 -+++ linux-5.5/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c 2020-03-11 18:24:09.196405329 +0200 -@@ -2639,7 +2639,7 @@ void rtw_cfg80211_unlink_bss(_adapter *p +diff -Nurp linux-5.11/3rdparty/rtl8812au.orig/os_dep/linux/ioctl_cfg80211.c linux-5.11/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c +--- linux-5.11/3rdparty/rtl8812au.orig/os_dep/linux/ioctl_cfg80211.c 2021-03-07 18:43:20.371675404 +0200 ++++ linux-5.11/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c 2021-03-07 18:43:51.402141772 +0200 +@@ -2646,7 +2646,7 @@ void rtw_cfg80211_unlink_bss(_adapter *p #endif if (!wiphy) { diff --git a/kernel/tools/perf/files/patches/mageia/3rd-rtl8812au.patch b/kernel/tools/perf/files/patches/mageia/3rd-rtl8812au.patch index 0d550052e3..891f72c573 100644 --- a/kernel/tools/perf/files/patches/mageia/3rd-rtl8812au.patch +++ b/kernel/tools/perf/files/patches/mageia/3rd-rtl8812au.patch @@ -1,2910 +1,6 @@ -Cloned from: - https://github.com/aircrack-ng/rtl8812au.git - -Signed-off-by: Nicolas Lécureuil ---- - -diff --git linux-5.8/3rdparty/rtl8812au/Kconfig linux-5.8/3rdparty/rtl8812au/Kconfig -new file mode 100644 -index 000000000..f63a78009 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/Kconfig -@@ -0,0 +1,6 @@ -+config 88XXAU -+ tristate "Realtek 88XXau USB WiFi" -+ depends on USB -+ ---help--- -+ Help message of 88XXau -+ -diff --git linux-5.8/3rdparty/rtl8812au/LICENSE linux-5.8/3rdparty/rtl8812au/LICENSE -new file mode 100644 -index 000000000..d159169d1 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/LICENSE -@@ -0,0 +1,339 @@ -+ GNU GENERAL PUBLIC LICENSE -+ Version 2, June 1991 -+ -+ Copyright (C) 1989, 1991 Free Software Foundation, Inc., -+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ Everyone is permitted to copy and distribute verbatim copies -+ of this license document, but changing it is not allowed. -+ -+ Preamble -+ -+ The licenses for most software are designed to take away your -+freedom to share and change it. By contrast, the GNU General Public -+License is intended to guarantee your freedom to share and change free -+software--to make sure the software is free for all its users. This -+General Public License applies to most of the Free Software -+Foundation's software and to any other program whose authors commit to -+using it. (Some other Free Software Foundation software is covered by -+the GNU Lesser General Public License instead.) You can apply it to -+your programs, too. -+ -+ When we speak of free software, we are referring to freedom, not -+price. Our General Public Licenses are designed to make sure that you -+have the freedom to distribute copies of free software (and charge for -+this service if you wish), that you receive source code or can get it -+if you want it, that you can change the software or use pieces of it -+in new free programs; and that you know you can do these things. -+ -+ To protect your rights, we need to make restrictions that forbid -+anyone to deny you these rights or to ask you to surrender the rights. -+These restrictions translate to certain responsibilities for you if you -+distribute copies of the software, or if you modify it. -+ -+ For example, if you distribute copies of such a program, whether -+gratis or for a fee, you must give the recipients all the rights that -+you have. You must make sure that they, too, receive or can get the -+source code. And you must show them these terms so they know their -+rights. -+ -+ We protect your rights with two steps: (1) copyright the software, and -+(2) offer you this license which gives you legal permission to copy, -+distribute and/or modify the software. -+ -+ Also, for each author's protection and ours, we want to make certain -+that everyone understands that there is no warranty for this free -+software. If the software is modified by someone else and passed on, we -+want its recipients to know that what they have is not the original, so -+that any problems introduced by others will not reflect on the original -+authors' reputations. -+ -+ Finally, any free program is threatened constantly by software -+patents. We wish to avoid the danger that redistributors of a free -+program will individually obtain patent licenses, in effect making the -+program proprietary. To prevent this, we have made it clear that any -+patent must be licensed for everyone's free use or not licensed at all. -+ -+ The precise terms and conditions for copying, distribution and -+modification follow. -+ -+ GNU GENERAL PUBLIC LICENSE -+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION -+ -+ 0. This License applies to any program or other work which contains -+a notice placed by the copyright holder saying it may be distributed -+under the terms of this General Public License. The "Program", below, -+refers to any such program or work, and a "work based on the Program" -+means either the Program or any derivative work under copyright law: -+that is to say, a work containing the Program or a portion of it, -+either verbatim or with modifications and/or translated into another -+language. (Hereinafter, translation is included without limitation in -+the term "modification".) Each licensee is addressed as "you". -+ -+Activities other than copying, distribution and modification are not -+covered by this License; they are outside its scope. The act of -+running the Program is not restricted, and the output from the Program -+is covered only if its contents constitute a work based on the -+Program (independent of having been made by running the Program). -+Whether that is true depends on what the Program does. -+ -+ 1. You may copy and distribute verbatim copies of the Program's -+source code as you receive it, in any medium, provided that you -+conspicuously and appropriately publish on each copy an appropriate -+copyright notice and disclaimer of warranty; keep intact all the -+notices that refer to this License and to the absence of any warranty; -+and give any other recipients of the Program a copy of this License -+along with the Program. -+ -+You may charge a fee for the physical act of transferring a copy, and -+you may at your option offer warranty protection in exchange for a fee. -+ -+ 2. You may modify your copy or copies of the Program or any portion -+of it, thus forming a work based on the Program, and copy and -+distribute such modifications or work under the terms of Section 1 -+above, provided that you also meet all of these conditions: -+ -+ a) You must cause the modified files to carry prominent notices -+ stating that you changed the files and the date of any change. -+ -+ b) You must cause any work that you distribute or publish, that in -+ whole or in part contains or is derived from the Program or any -+ part thereof, to be licensed as a whole at no charge to all third -+ parties under the terms of this License. -+ -+ c) If the modified program normally reads commands interactively -+ when run, you must cause it, when started running for such -+ interactive use in the most ordinary way, to print or display an -+ announcement including an appropriate copyright notice and a -+ notice that there is no warranty (or else, saying that you provide -+ a warranty) and that users may redistribute the program under -+ these conditions, and telling the user how to view a copy of this -+ License. (Exception: if the Program itself is interactive but -+ does not normally print such an announcement, your work based on -+ the Program is not required to print an announcement.) -+ -+These requirements apply to the modified work as a whole. If -+identifiable sections of that work are not derived from the Program, -+and can be reasonably considered independent and separate works in -+themselves, then this License, and its terms, do not apply to those -+sections when you distribute them as separate works. But when you -+distribute the same sections as part of a whole which is a work based -+on the Program, the distribution of the whole must be on the terms of -+this License, whose permissions for other licensees extend to the -+entire whole, and thus to each and every part regardless of who wrote it. -+ -+Thus, it is not the intent of this section to claim rights or contest -+your rights to work written entirely by you; rather, the intent is to -+exercise the right to control the distribution of derivative or -+collective works based on the Program. -+ -+In addition, mere aggregation of another work not based on the Program -+with the Program (or with a work based on the Program) on a volume of -+a storage or distribution medium does not bring the other work under -+the scope of this License. -+ -+ 3. You may copy and distribute the Program (or a work based on it, -+under Section 2) in object code or executable form under the terms of -+Sections 1 and 2 above provided that you also do one of the following: -+ -+ a) Accompany it with the complete corresponding machine-readable -+ source code, which must be distributed under the terms of Sections -+ 1 and 2 above on a medium customarily used for software interchange; or, -+ -+ b) Accompany it with a written offer, valid for at least three -+ years, to give any third party, for a charge no more than your -+ cost of physically performing source distribution, a complete -+ machine-readable copy of the corresponding source code, to be -+ distributed under the terms of Sections 1 and 2 above on a medium -+ customarily used for software interchange; or, -+ -+ c) Accompany it with the information you received as to the offer -+ to distribute corresponding source code. (This alternative is -+ allowed only for noncommercial distribution and only if you -+ received the program in object code or executable form with such -+ an offer, in accord with Subsection b above.) -+ -+The source code for a work means the preferred form of the work for -+making modifications to it. For an executable work, complete source -+code means all the source code for all modules it contains, plus any -+associated interface definition files, plus the scripts used to -+control compilation and installation of the executable. However, as a -+special exception, the source code distributed need not include -+anything that is normally distributed (in either source or binary -+form) with the major components (compiler, kernel, and so on) of the -+operating system on which the executable runs, unless that component -+itself accompanies the executable. -+ -+If distribution of executable or object code is made by offering -+access to copy from a designated place, then offering equivalent -+access to copy the source code from the same place counts as -+distribution of the source code, even though third parties are not -+compelled to copy the source along with the object code. -+ -+ 4. You may not copy, modify, sublicense, or distribute the Program -+except as expressly provided under this License. Any attempt -+otherwise to copy, modify, sublicense or distribute the Program is -+void, and will automatically terminate your rights under this License. -+However, parties who have received copies, or rights, from you under -+this License will not have their licenses terminated so long as such -+parties remain in full compliance. -+ -+ 5. You are not required to accept this License, since you have not -+signed it. However, nothing else grants you permission to modify or -+distribute the Program or its derivative works. These actions are -+prohibited by law if you do not accept this License. Therefore, by -+modifying or distributing the Program (or any work based on the -+Program), you indicate your acceptance of this License to do so, and -+all its terms and conditions for copying, distributing or modifying -+the Program or works based on it. -+ -+ 6. Each time you redistribute the Program (or any work based on the -+Program), the recipient automatically receives a license from the -+original licensor to copy, distribute or modify the Program subject to -+these terms and conditions. You may not impose any further -+restrictions on the recipients' exercise of the rights granted herein. -+You are not responsible for enforcing compliance by third parties to -+this License. -+ -+ 7. If, as a consequence of a court judgment or allegation of patent -+infringement or for any other reason (not limited to patent issues), -+conditions are imposed on you (whether by court order, agreement or -+otherwise) that contradict the conditions of this License, they do not -+excuse you from the conditions of this License. If you cannot -+distribute so as to satisfy simultaneously your obligations under this -+License and any other pertinent obligations, then as a consequence you -+may not distribute the Program at all. For example, if a patent -+license would not permit royalty-free redistribution of the Program by -+all those who receive copies directly or indirectly through you, then -+the only way you could satisfy both it and this License would be to -+refrain entirely from distribution of the Program. -+ -+If any portion of this section is held invalid or unenforceable under -+any particular circumstance, the balance of the section is intended to -+apply and the section as a whole is intended to apply in other -+circumstances. -+ -+It is not the purpose of this section to induce you to infringe any -+patents or other property right claims or to contest validity of any -+such claims; this section has the sole purpose of protecting the -+integrity of the free software distribution system, which is -+implemented by public license practices. Many people have made -+generous contributions to the wide range of software distributed -+through that system in reliance on consistent application of that -+system; it is up to the author/donor to decide if he or she is willing -+to distribute software through any other system and a licensee cannot -+impose that choice. -+ -+This section is intended to make thoroughly clear what is believed to -+be a consequence of the rest of this License. -+ -+ 8. If the distribution and/or use of the Program is restricted in -+certain countries either by patents or by copyrighted interfaces, the -+original copyright holder who places the Program under this License -+may add an explicit geographical distribution limitation excluding -+those countries, so that distribution is permitted only in or among -+countries not thus excluded. In such case, this License incorporates -+the limitation as if written in the body of this License. -+ -+ 9. The Free Software Foundation may publish revised and/or new versions -+of the General Public License from time to time. Such new versions will -+be similar in spirit to the present version, but may differ in detail to -+address new problems or concerns. -+ -+Each version is given a distinguishing version number. If the Program -+specifies a version number of this License which applies to it and "any -+later version", you have the option of following the terms and conditions -+either of that version or of any later version published by the Free -+Software Foundation. If the Program does not specify a version number of -+this License, you may choose any version ever published by the Free Software -+Foundation. -+ -+ 10. If you wish to incorporate parts of the Program into other free -+programs whose distribution conditions are different, write to the author -+to ask for permission. For software which is copyrighted by the Free -+Software Foundation, write to the Free Software Foundation; we sometimes -+make exceptions for this. Our decision will be guided by the two goals -+of preserving the free status of all derivatives of our free software and -+of promoting the sharing and reuse of software generally. -+ -+ NO WARRANTY -+ -+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -+REPAIR OR CORRECTION. -+ -+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -+POSSIBILITY OF SUCH DAMAGES. -+ -+ END OF TERMS AND CONDITIONS -+ -+ How to Apply These Terms to Your New Programs -+ -+ If you develop a new program, and you want it to be of the greatest -+possible use to the public, the best way to achieve this is to make it -+free software which everyone can redistribute and change under these terms. -+ -+ To do so, attach the following notices to the program. It is safest -+to attach them to the start of each source file to most effectively -+convey the exclusion of warranty; and each file should have at least -+the "copyright" line and a pointer to where the full notice is found. -+ -+ -+ Copyright (C) -+ -+ This program is free software; you can redistribute it and/or modify -+ it under the terms of the GNU General Public License as published by -+ the Free Software Foundation; either version 2 of the License, or -+ (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License along -+ with this program; if not, write to the Free Software Foundation, Inc., -+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ -+Also add information on how to contact you by electronic and paper mail. -+ -+If the program is interactive, make it output a short notice like this -+when it starts in an interactive mode: -+ -+ Gnomovision version 69, Copyright (C) year name of author -+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. -+ This is free software, and you are welcome to redistribute it -+ under certain conditions; type `show c' for details. -+ -+The hypothetical commands `show w' and `show c' should show the appropriate -+parts of the General Public License. Of course, the commands you use may -+be called something other than `show w' and `show c'; they could even be -+mouse-clicks or menu items--whatever suits your program. -+ -+You should also get your employer (if you work as a programmer) or your -+school, if any, to sign a "copyright disclaimer" for the program, if -+necessary. Here is a sample; alter the names: -+ -+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program -+ `Gnomovision' (which makes passes at compilers) written by James Hacker. -+ -+ , 1 April 1989 -+ Ty Coon, President of Vice -+ -+This General Public License does not permit incorporating your program into -+proprietary programs. If your program is a subroutine library, you may -+consider it more useful to permit linking proprietary applications with the -+library. If this is what you want to do, use the GNU Lesser General -+Public License instead of this License. -diff --git linux-5.8/3rdparty/rtl8812au/Makefile linux-5.8/3rdparty/rtl8812au/Makefile -new file mode 100755 -index 000000000..27daceded ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/Makefile -@@ -0,0 +1,2316 @@ -+EXTRA_CFLAGS += $(USER_EXTRA_CFLAGS) -fno-pie -+EXTRA_CFLAGS += -O3 -+EXTRA_CFLAGS += -Wno-unused-variable -+#EXTRA_CFLAGS += -Wno-unused-value -+EXTRA_CFLAGS += -Wno-unused-label -+#EXTRA_CFLAGS += -Wno-unused-parameter -+EXTRA_CFLAGS += -Wno-unused-function -+EXTRA_CFLAGS += -Wimplicit-fallthrough=0 -+#EXTRA_CFLAGS += -Wno-parentheses-equality -+#EXTRA_CFLAGS += -Wno-pointer-bool-conversion -+EXTRA_CFLAGS += -Wno-unknown-pragmas -+#EXTRA_CFLAGS += -Wno-unused -+EXTRA_CFLAGS += -Wno-vla -g -+ -+#GCC_VER_49 := $(shell echo `$(CC) -dumpversion | cut -f1-2 -d.` \>= 4.9 | bc ) -+#ifeq ($(GCC_VER_49),1) -+#EXTRA_CFLAGS += -Wno-date-time # Fix compile error && warning on gcc 4.9 and later -+#endif -+ -+EXTRA_CFLAGS += -I$(src)/include -+EXTRA_LDFLAGS += --strip-all -O3 -+ -+########################## WIFI IC ############################ -+CONFIG_RTL8812A = y -+CONFIG_RTL8821A = y -+CONFIG_RTL8814A = y -+######################### Interface ########################### -+CONFIG_USB_HCI = y -+########################### Android ########################### -+CONFIG_SIGNAL_DISPLAY_DBM = y -+########################## Features ########################### -+CONFIG_NET_NS = y -+CONFIG_MP_INCLUDED = y -+CONFIG_POWER_SAVING = n -+CONFIG_USB_AUTOSUSPEND = n -+CONFIG_HW_PWRP_DETECTION = n -+CONFIG_BT_COEXIST = n -+CONFIG_INTEL_WIDI = n -+CONFIG_WAPI_SUPPORT = n -+CONFIG_EFUSE_CONFIG_FILE = y -+CONFIG_EXT_CLK = n -+CONFIG_TRAFFIC_PROTECT = n -+CONFIG_LOAD_PHY_PARA_FROM_FILE = y -+CONFIG_TXPWR_BY_RATE = y -+CONFIG_TXPWR_BY_RATE_EN = n -+CONFIG_TXPWR_LIMIT = y -+CONFIG_TXPWR_LIMIT_EN = n -+CONFIG_RTW_CHPLAN = 0xFF -+CONFIG_RTW_ADAPTIVITY_EN = disable -+CONFIG_RTW_ADAPTIVITY_MODE = normal -+CONFIG_SIGNAL_SCALE_MAPPING = n -+CONFIG_80211W = y -+CONFIG_REDUCE_TX_CPU_LOADING = n -+CONFIG_BR_EXT = y -+CONFIG_TDLS = n -+CONFIG_WIFI_MONITOR = y -+CONFIG_DISABLE_REGD_C = y -+CONFIG_MCC_MODE = n -+CONFIG_APPEND_VENDOR_IE_ENABLE = n -+CONFIG_RTW_NAPI = y -+CONFIG_RTW_GRO = y -+CONFIG_RTW_NETIF_SG = y -+CONFIG_TX_CSUM_OFFLOAD = n -+CONFIG_RTW_IPCAM_APPLICATION = n -+CONFIG_RTW_REPEATER_SON = n -+CONFIG_RTW_WIFI_HAL = n -+CONFIG_ICMP_VOQ = n -+CONFIG_IP_R_MONITOR = n #arp VOQ and high rate -+########################## Debug ########################### -+CONFIG_RTW_DEBUG = n -+# default log level is _DRV_INFO_ = 4, -+# please refer to "How_to_set_driver_debug_log_level.doc" to set the available level. -+CONFIG_RTW_LOG_LEVEL = 2 -+######################## Wake On Lan ########################## -+CONFIG_WOWLAN = n -+#bit2: deauth, bit1: unicast, bit0: magic pkt. -+CONFIG_WAKEUP_TYPE = 0x7 -+#bit0: disBBRF off, #bit1: Wireless remote controller (WRC) -+CONFIG_SUSPEND_TYPE = 0 -+CONFIG_WOW_STA_MIX = n -+CONFIG_GPIO_WAKEUP = n -+CONFIG_WAKEUP_GPIO_IDX = default -+CONFIG_HIGH_ACTIVE_DEV2HST = n -+######### only for USB ######### -+CONFIG_ONE_PIN_GPIO = n -+CONFIG_HIGH_ACTIVE_HST2DEV = n -+CONFIG_PNO_SUPPORT = n -+CONFIG_PNO_SET_DEBUG = n -+CONFIG_AP_WOWLAN = n -+######### Notify SDIO Host Keep Power During Syspend ########## -+CONFIG_RTW_SDIO_PM_KEEP_POWER = y -+###################### MP HW TX MODE FOR VHT ####################### -+CONFIG_MP_VHT_HW_TX_MODE = n -+###################### Platform Related ####################### -+CONFIG_PLATFORM_I386_PC = y -+CONFIG_PLATFORM_ANDROID_ARM64 = n -+CONFIG_PLATFORM_ARM_RPI = n -+CONFIG_PLATFORM_ARM64_RPI = n -+CONFIG_PLATFORM_ARM_NV_NANO = n -+CONFIG_PLATFORM_ANDROID_X86 = n -+CONFIG_PLATFORM_ANDROID_INTEL_X86 = n -+CONFIG_PLATFORM_JB_X86 = n -+CONFIG_PLATFORM_OPENWRT_NEO2 = n -+CONFIG_PLATFORM_ARM_S3C2K4 = n -+CONFIG_PLATFORM_ARM_PXA2XX = n -+CONFIG_PLATFORM_ARM_S3C6K4 = n -+CONFIG_PLATFORM_MIPS_RMI = n -+CONFIG_PLATFORM_RTD2880B = n -+CONFIG_PLATFORM_MIPS_AR9132 = n -+CONFIG_PLATFORM_RTK_DMP = n -+CONFIG_PLATFORM_MIPS_PLM = n -+CONFIG_PLATFORM_MSTAR389 = n -+CONFIG_PLATFORM_MT53XX = n -+CONFIG_PLATFORM_ARM_MX51_241H = n -+CONFIG_PLATFORM_FS_MX61 = n -+CONFIG_PLATFORM_ACTIONS_ATJ227X = n -+CONFIG_PLATFORM_TEGRA3_CARDHU = n -+CONFIG_PLATFORM_TEGRA4_DALMORE = n -+CONFIG_PLATFORM_ARM_TCC8900 = n -+CONFIG_PLATFORM_ARM_TCC8920 = n -+CONFIG_PLATFORM_ARM_TCC8920_JB42 = n -+CONFIG_PLATFORM_ARM_TCC8930_JB42 = n -+CONFIG_PLATFORM_ARM_RK2818 = n -+CONFIG_PLATFORM_ARM_RK3066 = n -+CONFIG_PLATFORM_ARM_RK3188 = n -+CONFIG_PLATFORM_ARM_URBETTER = n -+CONFIG_PLATFORM_ARM_TI_PANDA = n -+CONFIG_PLATFORM_MIPS_JZ4760 = n -+CONFIG_PLATFORM_DMP_PHILIPS = n -+CONFIG_PLATFORM_MSTAR_TITANIA12 = n -+CONFIG_PLATFORM_MSTAR = n -+CONFIG_PLATFORM_SZEBOOK = n -+CONFIG_PLATFORM_ARM_SUNxI = n -+CONFIG_PLATFORM_ARM_SUN6I = n -+CONFIG_PLATFORM_ARM_SUN7I = n -+CONFIG_PLATFORM_ARM_SUN8I_W3P1 = n -+CONFIG_PLATFORM_ARM_SUN8I_W5P1 = n -+CONFIG_PLATFORM_ACTIONS_ATM702X = n -+CONFIG_PLATFORM_ACTIONS_ATV5201 = n -+CONFIG_PLATFORM_ACTIONS_ATM705X = n -+CONFIG_PLATFORM_ARM_SUN50IW1P1 = n -+CONFIG_PLATFORM_ARM_RTD299X = n -+CONFIG_PLATFORM_ARM_LGE = n -+CONFIG_PLATFORM_ARM_SPREADTRUM_6820 = n -+CONFIG_PLATFORM_ARM_SPREADTRUM_8810 = n -+CONFIG_PLATFORM_ARM_WMT = n -+CONFIG_PLATFORM_TI_DM365 = n -+CONFIG_PLATFORM_MOZART = n -+CONFIG_PLATFORM_RTK119X = n -+CONFIG_PLATFORM_RTK119X_AM = n -+CONFIG_PLATFORM_RTK129X = n -+CONFIG_PLATFORM_RTK390X = n -+CONFIG_PLATFORM_NOVATEK_NT72668 = n -+CONFIG_PLATFORM_HISILICON = n -+CONFIG_PLATFORM_HISILICON_HI3798 = n -+CONFIG_PLATFORM_NV_TK1 = n -+CONFIG_PLATFORM_NV_TK1_UBUNTU = n -+CONFIG_PLATFORM_RTL8197D = n -+CONFIG_PLATFORM_AML_S905 = n -+CONFIG_PLATFORM_ZTE_ZX296716 = n -+CONFIG_PLATFORM_ARM_ODROIDC2 = n -+CONFIG_PLATFORM_PPC = n -+########### CUSTOMER ################################ -+CONFIG_CUSTOMER_HUAWEI_GENERAL = n -+ -+CONFIG_DRVEXT_MODULE = n -+ -+ifeq ($(CONFIG_RTL8812AU), ) -+ifneq (,$(findstring /usr/lib/dkms,$(PATH))) -+ export TopDIR ?= $(shell pwd) -+else -+export TopDIR ?= $(srctree)/$(src) -+endif -+endif -+ -+########### COMMON ################################# -+ifeq ($(CONFIG_USB_HCI), y) -+HCI_NAME = usb -+endif -+ -+ifeq ($(CONFIG_RTL8812A)_$(CONFIG_RTL8821A)_$(CONFIG_RTL8814A), y_y_y) -+ -+EXTRA_CFLAGS += -DDRV_NAME=\"rtl88XXau\" -+ifeq ($(CONFIG_USB_HCI), y) -+USER_MODULE_NAME = 88XXau -+endif -+else -+EXTRA_CFLAGS += -DDRV_NAME=\"rtl8812au\" -+endif -+ -+_OS_INTFS_FILES := os_dep/osdep_service.o \ -+ os_dep/linux/os_intfs.o \ -+ os_dep/linux/$(HCI_NAME)_intf.o \ -+ os_dep/linux/$(HCI_NAME)_ops_linux.o \ -+ os_dep/linux/ioctl_linux.o \ -+ os_dep/linux/xmit_linux.o \ -+ os_dep/linux/mlme_linux.o \ -+ os_dep/linux/recv_linux.o \ -+ os_dep/linux/ioctl_cfg80211.o \ -+ os_dep/linux/wifi_regd.o \ -+ os_dep/linux/rtw_android.o \ -+ os_dep/linux/rtw_proc.o \ -+ os_dep/linux/rtw_rhashtable.o -+ -+ifeq ($(CONFIG_MP_INCLUDED), y) -+_OS_INTFS_FILES += os_dep/linux/ioctl_mp.o -+endif -+ -+_HAL_INTFS_FILES := hal/hal_intf.o \ -+ hal/hal_com.o \ -+ hal/hal_com_phycfg.o \ -+ hal/hal_phy.o \ -+ hal/hal_dm.o \ -+ hal/hal_dm_acs.o \ -+ hal/hal_btcoex_wifionly.o \ -+ hal/hal_btcoex.o \ -+ hal/hal_mp.o \ -+ hal/hal_mcc.o \ -+ hal/hal_hci/hal_$(HCI_NAME).o \ -+ hal/led/hal_led.o \ -+ hal/led/hal_$(HCI_NAME)_led.o -+ -+ -+EXTRA_CFLAGS += -I$(src)/platform -+_PLATFORM_FILES := platform/platform_ops.o -+ -+EXTRA_CFLAGS += -I$(src)/hal/btc -+ -+########### HAL_RTL8188E ################################# -+ifeq ($(CONFIG_RTL8188E), y) -+ -+RTL871X = rtl8188e -+ifeq ($(CONFIG_SDIO_HCI), y) -+MODULE_NAME = 8189es -+endif -+ -+ifeq ($(CONFIG_GSPI_HCI), y) -+MODULE_NAME = 8189es -+endif -+ -+ifeq ($(CONFIG_USB_HCI), y) -+MODULE_NAME = 8188eu -+endif -+ -+ifeq ($(CONFIG_PCI_HCI), y) -+MODULE_NAME = 8188ee -+endif -+EXTRA_CFLAGS += -DCONFIG_RTL8188E -+ -+_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ -+ hal/$(RTL871X)/Hal8188EPwrSeq.o\ -+ hal/$(RTL871X)/$(RTL871X)_xmit.o\ -+ hal/$(RTL871X)/$(RTL871X)_sreset.o -+ -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ -+ hal/$(RTL871X)/$(RTL871X)_phycfg.o \ -+ hal/$(RTL871X)/$(RTL871X)_rf6052.o \ -+ hal/$(RTL871X)/$(RTL871X)_dm.o \ -+ hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ -+ hal/$(RTL871X)/$(RTL871X)_cmd.o \ -+ hal/$(RTL871X)/hal8188e_s_fw.o \ -+ hal/$(RTL871X)/hal8188e_t_fw.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o -+ -+ifeq ($(CONFIG_SDIO_HCI), y) -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o -+else -+ifeq ($(CONFIG_GSPI_HCI), y) -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o -+else -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o -+endif -+endif -+ -+ifeq ($(CONFIG_USB_HCI), y) -+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188E_USB.o -+endif -+ifeq ($(CONFIG_PCI_HCI), y) -+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188E_PCIE.o -+endif -+ifeq ($(CONFIG_SDIO_HCI), y) -+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188E_SDIO.o -+endif -+endif -+ -+########### HAL_RTL8812A_RTL8821A ################################# -+ -+ifneq ($(CONFIG_RTL8812A)_$(CONFIG_RTL8821A), n_n) -+ -+RTL871X = rtl8812a -+ifeq ($(CONFIG_USB_HCI), y) -+MODULE_NAME = 8812au -+endif -+ifeq ($(CONFIG_PCI_HCI), y) -+MODULE_NAME = 8812ae -+endif -+ifeq ($(CONFIG_SDIO_HCI), y) -+MODULE_NAME = 8812as -+endif -+ -+_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ -+ hal/$(RTL871X)/Hal8812PwrSeq.o \ -+ hal/$(RTL871X)/Hal8821APwrSeq.o\ -+ hal/$(RTL871X)/$(RTL871X)_xmit.o\ -+ hal/$(RTL871X)/$(RTL871X)_sreset.o -+ -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ -+ hal/$(RTL871X)/$(RTL871X)_phycfg.o \ -+ hal/$(RTL871X)/$(RTL871X)_rf6052.o \ -+ hal/$(RTL871X)/$(RTL871X)_dm.o \ -+ hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ -+ hal/$(RTL871X)/$(RTL871X)_cmd.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o -+ -+ifeq ($(CONFIG_SDIO_HCI), y) -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o -+else -+ifeq ($(CONFIG_GSPI_HCI), y) -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o -+else -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o -+endif -+endif -+ -+ifeq ($(CONFIG_RTL8812A), y) -+ifeq ($(CONFIG_USB_HCI), y) -+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8812A_USB.o -+endif -+ifeq ($(CONFIG_PCI_HCI), y) -+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8812A_PCIE.o -+endif -+endif -+ifeq ($(CONFIG_RTL8821A), y) -+ifeq ($(CONFIG_USB_HCI), y) -+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8821A_USB.o -+endif -+ifeq ($(CONFIG_PCI_HCI), y) -+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8821A_PCIE.o -+endif -+ifeq ($(CONFIG_SDIO_HCI), y) -+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8821A_SDIO.o -+endif -+endif -+ -+ifeq ($(CONFIG_RTL8812A), y) -+EXTRA_CFLAGS += -DCONFIG_RTL8812A -+_HAL_INTFS_FILES += hal/rtl8812a/hal8812a_fw.o -+endif -+ -+ifeq ($(CONFIG_RTL8821A), y) -+ -+ifeq ($(CONFIG_RTL8812A), n) -+ -+RTL871X = rtl8821a -+ifeq ($(CONFIG_USB_HCI), y) -+ifeq ($(CONFIG_BT_COEXIST), y) -+MODULE_NAME := 8821au -+else -+MODULE_NAME := 8811au -+endif -+endif -+ifeq ($(CONFIG_PCI_HCI), y) -+MODULE_NAME := 8821ae -+endif -+ifeq ($(CONFIG_SDIO_HCI), y) -+MODULE_NAME := 8821as -+endif -+ -+endif -+ -+EXTRA_CFLAGS += -DCONFIG_RTL8821A -+ -+_HAL_INTFS_FILES += hal/rtl8812a/hal8821a_fw.o -+ -+endif -+ -+ifeq ($(CONFIG_BT_COEXIST), y) -+ifeq ($(CONFIG_RTL8812A), y) -+_BTC_FILES += hal/btc/halbtc8812a1ant.o \ -+ hal/btc/halbtc8812a2ant.o -+endif -+ifeq ($(CONFIG_RTL8821A), y) -+_BTC_FILES += hal/btc/halbtc8821a1ant.o \ -+ hal/btc/halbtc8821a2ant.o -+endif -+endif -+ -+endif -+ -+########### HAL_RTL8723B ################################# -+ifeq ($(CONFIG_RTL8723B), y) -+ -+RTL871X = rtl8723b -+ifeq ($(CONFIG_USB_HCI), y) -+MODULE_NAME = 8723bu -+endif -+ifeq ($(CONFIG_PCI_HCI), y) -+MODULE_NAME = 8723be -+endif -+ifeq ($(CONFIG_SDIO_HCI), y) -+MODULE_NAME = 8723bs -+endif -+ -+EXTRA_CFLAGS += -DCONFIG_RTL8723B -+ -+_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ -+ hal/$(RTL871X)/Hal8723BPwrSeq.o\ -+ hal/$(RTL871X)/$(RTL871X)_sreset.o -+ -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ -+ hal/$(RTL871X)/$(RTL871X)_phycfg.o \ -+ hal/$(RTL871X)/$(RTL871X)_rf6052.o \ -+ hal/$(RTL871X)/$(RTL871X)_dm.o \ -+ hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ -+ hal/$(RTL871X)/$(RTL871X)_cmd.o \ -+ hal/$(RTL871X)/hal8723b_fw.o -+ -+_HAL_INTFS_FILES += \ -+ hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o -+ -+ifeq ($(CONFIG_PCI_HCI), y) -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o -+else -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o -+endif -+ -+ifeq ($(CONFIG_USB_HCI), y) -+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8723B_USB.o -+endif -+ifeq ($(CONFIG_PCI_HCI), y) -+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8723B_PCIE.o -+endif -+ifeq ($(CONFIG_SDIO_HCI), y) -+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8723B_SDIO.o -+endif -+ -+_BTC_FILES += hal/btc/halbtc8723bwifionly.o -+ifeq ($(CONFIG_BT_COEXIST), y) -+_BTC_FILES += hal/btc/halbtc8723b1ant.o \ -+ hal/btc/halbtc8723b2ant.o -+endif -+ -+endif -+ -+########### HAL_RTL8814A ################################# -+ifeq ($(CONFIG_RTL8814A), y) -+## ADD NEW VHT MP HW TX MODE ## -+#EXTRA_CFLAGS += -DCONFIG_MP_VHT_HW_TX_MODE -+CONFIG_MP_VHT_HW_TX_MODE = n -+########################################## -+RTL871X = rtl8814a -+ifeq ($(CONFIG_USB_HCI), y) -+MODULE_NAME = 8814au -+endif -+ -+EXTRA_CFLAGS += -DCONFIG_RTL8814A -+ -+_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ -+ hal/$(RTL871X)/Hal8814PwrSeq.o \ -+ hal/$(RTL871X)/$(RTL871X)_xmit.o\ -+ hal/$(RTL871X)/$(RTL871X)_sreset.o -+ -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ -+ hal/$(RTL871X)/$(RTL871X)_phycfg.o \ -+ hal/$(RTL871X)/$(RTL871X)_rf6052.o \ -+ hal/$(RTL871X)/$(RTL871X)_dm.o \ -+ hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ -+ hal/$(RTL871X)/$(RTL871X)_cmd.o \ -+ hal/$(RTL871X)/hal8814a_fw.o -+ -+ -+_HAL_INTFS_FILES += \ -+ hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o -+ -+ifeq ($(CONFIG_SDIO_HCI), y) -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o -+else -+ifeq ($(CONFIG_GSPI_HCI), y) -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o -+else -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o -+endif -+endif -+ -+ifeq ($(CONFIG_USB_HCI), y) -+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8814A_USB.o -+endif -+ifeq ($(CONFIG_PCI_HCI), y) -+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8814A_PCIE.o -+endif -+ -+endif -+ -+########### HAL_RTL8723C ################################# -+ifeq ($(CONFIG_RTL8723C), y) -+ -+RTL871X = rtl8703b -+ifeq ($(CONFIG_USB_HCI), y) -+MODULE_NAME = 8723cu -+MODULE_SUB_NAME = 8703bu -+endif -+ifeq ($(CONFIG_PCI_HCI), y) -+MODULE_NAME = 8723ce -+MODULE_SUB_NAME = 8703be -+endif -+ifeq ($(CONFIG_SDIO_HCI), y) -+MODULE_NAME = 8723cs -+MODULE_SUB_NAME = 8703bs -+endif -+ -+EXTRA_CFLAGS += -DCONFIG_RTL8703B -+ -+_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ -+ hal/$(RTL871X)/Hal8703BPwrSeq.o\ -+ hal/$(RTL871X)/$(RTL871X)_sreset.o -+ -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ -+ hal/$(RTL871X)/$(RTL871X)_phycfg.o \ -+ hal/$(RTL871X)/$(RTL871X)_rf6052.o \ -+ hal/$(RTL871X)/$(RTL871X)_dm.o \ -+ hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ -+ hal/$(RTL871X)/$(RTL871X)_cmd.o \ -+ hal/$(RTL871X)/hal8703b_fw.o -+ -+_HAL_INTFS_FILES += \ -+ hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_led.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_xmit.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_recv.o -+ -+ifeq ($(CONFIG_PCI_HCI), y) -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o -+else -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o -+endif -+ -+ifeq ($(CONFIG_USB_HCI), y) -+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8703B_USB.o -+endif -+ifeq ($(CONFIG_PCI_HCI), y) -+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8703B_PCIE.o -+endif -+ -+ifeq ($(CONFIG_BT_COEXIST), y) -+_BTC_FILES += hal/btc/halbtc8703b1ant.o -+endif -+ -+endif -+ -+########### HAL_RTL8723D ################################# -+ifeq ($(CONFIG_RTL8723D), y) -+ -+RTL871X = rtl8723d -+ifeq ($(CONFIG_USB_HCI), y) -+MODULE_NAME = 8723du -+MODULE_SUB_NAME = 8723du -+endif -+ifeq ($(CONFIG_PCI_HCI), y) -+MODULE_NAME = 8723de -+MODULE_SUB_NAME = 8723de -+endif -+ifeq ($(CONFIG_SDIO_HCI), y) -+MODULE_NAME = 8723ds -+MODULE_SUB_NAME = 8723ds -+endif -+ -+EXTRA_CFLAGS += -DCONFIG_RTL8723D -+ -+_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ -+ hal/$(RTL871X)/Hal8723DPwrSeq.o\ -+ hal/$(RTL871X)/$(RTL871X)_sreset.o -+ -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ -+ hal/$(RTL871X)/$(RTL871X)_phycfg.o \ -+ hal/$(RTL871X)/$(RTL871X)_rf6052.o \ -+ hal/$(RTL871X)/$(RTL871X)_dm.o \ -+ hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ -+ hal/$(RTL871X)/$(RTL871X)_cmd.o \ -+ hal/$(RTL871X)/hal8723d_fw.o \ -+ hal/$(RTL871X)/$(RTL871X)_lps_poff.o -+ -+ -+_HAL_INTFS_FILES += \ -+ hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_led.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_xmit.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_recv.o -+ -+ifeq ($(CONFIG_PCI_HCI), y) -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o -+else -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o -+endif -+ -+ifeq ($(CONFIG_USB_HCI), y) -+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8723D_USB.o -+endif -+ifeq ($(CONFIG_PCI_HCI), y) -+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8723D_PCIE.o -+endif -+ -+ifeq ($(CONFIG_BT_COEXIST), y) -+_BTC_FILES += hal/btc/halbtc8723d1ant.o \ -+ hal/btc/halbtc8723d2ant.o -+endif -+ -+endif -+ -+########### HAL_RTL8188F ################################# -+ifeq ($(CONFIG_RTL8188F), y) -+ -+RTL871X = rtl8188f -+ifeq ($(CONFIG_USB_HCI), y) -+MODULE_NAME = 8188fu -+endif -+ifeq ($(CONFIG_PCI_HCI), y) -+MODULE_NAME = 8188fe -+endif -+ifeq ($(CONFIG_SDIO_HCI), y) -+MODULE_NAME = 8189fs -+endif -+ -+EXTRA_CFLAGS += -DCONFIG_RTL8188F -+ -+_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ -+ hal/$(RTL871X)/Hal8188FPwrSeq.o\ -+ hal/$(RTL871X)/$(RTL871X)_sreset.o -+ -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ -+ hal/$(RTL871X)/$(RTL871X)_phycfg.o \ -+ hal/$(RTL871X)/$(RTL871X)_rf6052.o \ -+ hal/$(RTL871X)/$(RTL871X)_dm.o \ -+ hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ -+ hal/$(RTL871X)/$(RTL871X)_cmd.o \ -+ hal/$(RTL871X)/hal8188f_fw.o -+ -+_HAL_INTFS_FILES += \ -+ hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o -+ -+ifeq ($(CONFIG_PCI_HCI), y) -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o -+else -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o -+endif -+ -+ifeq ($(CONFIG_USB_HCI), y) -+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188F_USB.o -+endif -+ -+ifeq ($(CONFIG_SDIO_HCI), y) -+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188F_SDIO.o -+endif -+ -+endif -+ -+########### HAL_RTL8188GTV ################################# -+ifeq ($(CONFIG_RTL8188GTV), y) -+ -+RTL871X = rtl8188gtv -+ifeq ($(CONFIG_USB_HCI), y) -+MODULE_NAME = 8188gtvu -+endif -+ifeq ($(CONFIG_SDIO_HCI), y) -+MODULE_NAME = 8189gtvs -+endif -+ -+EXTRA_CFLAGS += -DCONFIG_RTL8188GTV -+ -+_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ -+ hal/$(RTL871X)/Hal8188GTVPwrSeq.o\ -+ hal/$(RTL871X)/$(RTL871X)_sreset.o -+ -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ -+ hal/$(RTL871X)/$(RTL871X)_phycfg.o \ -+ hal/$(RTL871X)/$(RTL871X)_rf6052.o \ -+ hal/$(RTL871X)/$(RTL871X)_dm.o \ -+ hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ -+ hal/$(RTL871X)/$(RTL871X)_cmd.o \ -+ hal/$(RTL871X)/hal8188gtv_fw.o -+ -+_HAL_INTFS_FILES += \ -+ hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o -+ -+ifeq ($(CONFIG_PCI_HCI), y) -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o -+else -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o -+endif -+ -+ifeq ($(CONFIG_USB_HCI), y) -+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188GTV_USB.o -+endif -+ -+ifeq ($(CONFIG_SDIO_HCI), y) -+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188GTV_SDIO.o -+endif -+ -+endif -+ -+########### HAL_RTL8822B ################################# -+ifeq ($(CONFIG_RTL8822B), y) -+RTL871X := rtl8822b -+ifeq ($(CONFIG_USB_HCI), y) -+ifeq ($(CONFIG_BT_COEXIST), n) -+MODULE_NAME = 8812bu -+else -+MODULE_NAME = 88x2bu -+endif -+endif -+ifeq ($(CONFIG_PCI_HCI), y) -+MODULE_NAME = 88x2be -+endif -+ifeq ($(CONFIG_SDIO_HCI), y) -+MODULE_NAME = 88x2bs -+endif -+ -+endif -+########### HAL_RTL8821C ################################# -+ifeq ($(CONFIG_RTL8821C), y) -+RTL871X := rtl8821c -+ifeq ($(CONFIG_USB_HCI), y) -+MODULE_NAME = 8821cu -+endif -+ifeq ($(CONFIG_PCI_HCI), y) -+MODULE_NAME = 8821ce -+endif -+ifeq ($(CONFIG_SDIO_HCI), y) -+MODULE_NAME = 8821cs -+endif -+ -+endif -+ -+########### HAL_RTL8710B ################################# -+ifeq ($(CONFIG_RTL8710B), y) -+ -+RTL871X = rtl8710b -+ifeq ($(CONFIG_USB_HCI), y) -+MODULE_NAME = 8710bu -+MODULE_SUB_NAME = 8710bu -+endif -+ -+EXTRA_CFLAGS += -DCONFIG_RTL8710B -+ -+_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ -+ hal/$(RTL871X)/Hal8710BPwrSeq.o\ -+ hal/$(RTL871X)/$(RTL871X)_sreset.o -+ -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ -+ hal/$(RTL871X)/$(RTL871X)_phycfg.o \ -+ hal/$(RTL871X)/$(RTL871X)_rf6052.o \ -+ hal/$(RTL871X)/$(RTL871X)_dm.o \ -+ hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ -+ hal/$(RTL871X)/$(RTL871X)_cmd.o \ -+ hal/$(RTL871X)/hal8710b_fw.o \ -+ hal/$(RTL871X)/$(RTL871X)_lps_poff.o -+ -+ -+_HAL_INTFS_FILES += \ -+ hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_led.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_xmit.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_recv.o -+ -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o -+ -+ifeq ($(CONFIG_USB_HCI), y) -+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8710B_USB.o -+endif -+ -+endif -+ -+########### HAL_RTL8192F ################################# -+ifeq ($(CONFIG_RTL8192F), y) -+ -+RTL871X = rtl8192f -+ifeq ($(CONFIG_USB_HCI), y) -+MODULE_NAME = 8192fu -+MODULE_SUB_NAME = 8192fu -+endif -+ifeq ($(CONFIG_PCI_HCI), y) -+MODULE_NAME = 8192fe -+MODULE_SUB_NAME = 8192fe -+endif -+ifeq ($(CONFIG_SDIO_HCI), y) -+MODULE_NAME = 8192fs -+MODULE_SUB_NAME = 8192fs -+endif -+ -+EXTRA_CFLAGS += -DCONFIG_RTL8192F -+ -+_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ -+ hal/$(RTL871X)/Hal8192FPwrSeq.o\ -+ hal/$(RTL871X)/$(RTL871X)_sreset.o -+ -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ -+ hal/$(RTL871X)/$(RTL871X)_phycfg.o \ -+ hal/$(RTL871X)/$(RTL871X)_rf6052.o \ -+ hal/$(RTL871X)/$(RTL871X)_dm.o \ -+ hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ -+ hal/$(RTL871X)/$(RTL871X)_cmd.o \ -+ hal/$(RTL871X)/hal8192f_fw.o \ -+ hal/$(RTL871X)/$(RTL871X)_lps_poff.o -+ -+ -+_HAL_INTFS_FILES += \ -+ hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_led.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_xmit.o \ -+ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_recv.o -+ -+ifeq ($(CONFIG_PCI_HCI), y) -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o -+else -+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o -+endif -+ -+ifeq ($(CONFIG_SDIO_HCI), y) -+_HAL_INTFS_FILES += hal/efuse/$(RTL871X)/HalEfuseMask8192F_SDIO.o -+endif -+ -+ifeq ($(CONFIG_USB_HCI), y) -+_HAL_INTFS_FILES += hal/efuse/$(RTL871X)/HalEfuseMask8192F_USB.o -+endif -+ -+ifeq ($(CONFIG_PCI_HCI), y) -+_HAL_INTFS_FILES += hal/efuse/$(RTL871X)/HalEfuseMask8192F_PCIE.o -+endif -+ -+endif -+########### AUTO_CFG ################################# -+ -+ifeq ($(CONFIG_AUTOCFG_CP), y) -+ -+ifeq ($(CONFIG_MULTIDRV), y) -+$(shell cp $(TopDIR)/autoconf_multidrv_$(HCI_NAME)_linux.h $(TopDIR)/include/autoconf.h) -+else -+ifeq ($(CONFIG_RTL8188E)$(CONFIG_SDIO_HCI),yy) -+$(shell cp $(TopDIR)/autoconf_rtl8189e_$(HCI_NAME)_linux.h $(TopDIR)/include/autoconf.h) -+else ifeq ($(CONFIG_RTL8188F)$(CONFIG_SDIO_HCI),yy) -+$(shell cp $(TopDIR)/autoconf_rtl8189f_$(HCI_NAME)_linux.h $(TopDIR)/include/autoconf.h) -+else ifeq ($(CONFIG_RTL8723C),y) -+$(shell cp $(TopDIR)/autoconf_rtl8723c_$(HCI_NAME)_linux.h $(TopDIR)/include/autoconf.h) -+else -+$(shell cp $(TopDIR)/autoconf_$(RTL871X)_$(HCI_NAME)_linux.h $(TopDIR)/include/autoconf.h) -+endif -+endif -+ -+endif -+ -+########### END OF PATH ################################# -+ -+ifeq ($(CONFIG_USB_HCI), y) -+ifeq ($(CONFIG_USB_AUTOSUSPEND), y) -+EXTRA_CFLAGS += -DCONFIG_USB_AUTOSUSPEND -+endif -+endif -+ -+ifeq ($(CONFIG_MP_INCLUDED), y) -+#MODULE_NAME := $(MODULE_NAME)_mp -+EXTRA_CFLAGS += -DCONFIG_MP_INCLUDED -+endif -+ -+ifeq ($(CONFIG_POWER_SAVING), y) -+EXTRA_CFLAGS += -DCONFIG_POWER_SAVING -+endif -+ -+ifeq ($(CONFIG_HW_PWRP_DETECTION), y) -+EXTRA_CFLAGS += -DCONFIG_HW_PWRP_DETECTION -+endif -+ -+ifeq ($(CONFIG_BT_COEXIST), y) -+EXTRA_CFLAGS += -DCONFIG_BT_COEXIST -+endif -+ -+ifeq ($(CONFIG_INTEL_WIDI), y) -+EXTRA_CFLAGS += -DCONFIG_INTEL_WIDI -+endif -+ -+ifeq ($(CONFIG_WAPI_SUPPORT), y) -+EXTRA_CFLAGS += -DCONFIG_WAPI_SUPPORT -+endif -+ -+ -+ifeq ($(CONFIG_EFUSE_CONFIG_FILE), y) -+EXTRA_CFLAGS += -DCONFIG_EFUSE_CONFIG_FILE -+ -+#EFUSE_MAP_PATH -+USER_EFUSE_MAP_PATH ?= -+ifneq ($(USER_EFUSE_MAP_PATH),) -+EXTRA_CFLAGS += -DEFUSE_MAP_PATH=\"$(USER_EFUSE_MAP_PATH)\" -+else ifeq ($(MODULE_NAME), 8189es) -+EXTRA_CFLAGS += -DEFUSE_MAP_PATH=\"/system/etc/wifi/wifi_efuse_8189e.map\" -+else ifeq ($(MODULE_NAME), 8723bs) -+EXTRA_CFLAGS += -DEFUSE_MAP_PATH=\"/system/etc/wifi/wifi_efuse_8723bs.map\" -+else -+EXTRA_CFLAGS += -DEFUSE_MAP_PATH=\"/system/etc/wifi/wifi_efuse_$(MODULE_NAME).map\" -+endif -+ -+#WIFIMAC_PATH -+USER_WIFIMAC_PATH ?= -+ifneq ($(USER_WIFIMAC_PATH),) -+EXTRA_CFLAGS += -DWIFIMAC_PATH=\"$(USER_WIFIMAC_PATH)\" -+else -+EXTRA_CFLAGS += -DWIFIMAC_PATH=\"/data/wifimac.txt\" -+endif -+ -+endif -+ -+ifeq ($(CONFIG_EXT_CLK), y) -+EXTRA_CFLAGS += -DCONFIG_EXT_CLK -+endif -+ -+ifeq ($(CONFIG_TRAFFIC_PROTECT), y) -+EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT -+endif -+ -+ifeq ($(CONFIG_LOAD_PHY_PARA_FROM_FILE), y) -+EXTRA_CFLAGS += -DCONFIG_LOAD_PHY_PARA_FROM_FILE -+#EXTRA_CFLAGS += -DREALTEK_CONFIG_PATH_WITH_IC_NAME_FOLDER -+EXTRA_CFLAGS += -DREALTEK_CONFIG_PATH=\"/lib/firmware/\" -+endif -+ -+ifeq ($(CONFIG_TXPWR_BY_RATE), n) -+EXTRA_CFLAGS += -DCONFIG_TXPWR_BY_RATE=0 -+else ifeq ($(CONFIG_TXPWR_BY_RATE), y) -+EXTRA_CFLAGS += -DCONFIG_TXPWR_BY_RATE=1 -+endif -+ifeq ($(CONFIG_TXPWR_BY_RATE_EN), n) -+EXTRA_CFLAGS += -DCONFIG_TXPWR_BY_RATE_EN=0 -+else ifeq ($(CONFIG_TXPWR_BY_RATE_EN), y) -+EXTRA_CFLAGS += -DCONFIG_TXPWR_BY_RATE_EN=1 -+else ifeq ($(CONFIG_TXPWR_BY_RATE_EN), auto) -+EXTRA_CFLAGS += -DCONFIG_TXPWR_BY_RATE_EN=2 -+endif -+ -+ifeq ($(CONFIG_TXPWR_LIMIT), n) -+EXTRA_CFLAGS += -DCONFIG_TXPWR_LIMIT=0 -+else ifeq ($(CONFIG_TXPWR_LIMIT), y) -+EXTRA_CFLAGS += -DCONFIG_TXPWR_LIMIT=1 -+endif -+ifeq ($(CONFIG_TXPWR_LIMIT_EN), n) -+EXTRA_CFLAGS += -DCONFIG_TXPWR_LIMIT_EN=0 -+else ifeq ($(CONFIG_TXPWR_LIMIT_EN), y) -+EXTRA_CFLAGS += -DCONFIG_TXPWR_LIMIT_EN=1 -+else ifeq ($(CONFIG_TXPWR_LIMIT_EN), auto) -+EXTRA_CFLAGS += -DCONFIG_TXPWR_LIMIT_EN=2 -+endif -+ -+ifneq ($(CONFIG_RTW_CHPLAN), 0xFF) -+EXTRA_CFLAGS += -DCONFIG_RTW_CHPLAN=$(CONFIG_RTW_CHPLAN) -+endif -+ -+ifeq ($(CONFIG_CALIBRATE_TX_POWER_BY_REGULATORY), y) -+EXTRA_CFLAGS += -DCONFIG_CALIBRATE_TX_POWER_BY_REGULATORY -+endif -+ -+ifeq ($(CONFIG_CALIBRATE_TX_POWER_TO_MAX), y) -+EXTRA_CFLAGS += -DCONFIG_CALIBRATE_TX_POWER_TO_MAX -+endif -+ -+ifeq ($(CONFIG_RTW_ADAPTIVITY_EN), disable) -+EXTRA_CFLAGS += -DCONFIG_RTW_ADAPTIVITY_EN=0 -+else ifeq ($(CONFIG_RTW_ADAPTIVITY_EN), enable) -+EXTRA_CFLAGS += -DCONFIG_RTW_ADAPTIVITY_EN=1 -+endif -+ -+ifeq ($(CONFIG_RTW_ADAPTIVITY_MODE), normal) -+EXTRA_CFLAGS += -DCONFIG_RTW_ADAPTIVITY_MODE=0 -+else ifeq ($(CONFIG_RTW_ADAPTIVITY_MODE), carrier_sense) -+EXTRA_CFLAGS += -DCONFIG_RTW_ADAPTIVITY_MODE=1 -+endif -+ -+ifeq ($(CONFIG_SIGNAL_SCALE_MAPPING), y) -+EXTRA_CFLAGS += -DCONFIG_SIGNAL_SCALE_MAPPING -+endif -+ -+ifeq ($(CONFIG_80211W), y) -+EXTRA_CFLAGS += -DCONFIG_IEEE80211W -+endif -+ -+ifeq ($(CONFIG_WOWLAN), y) -+EXTRA_CFLAGS += -DCONFIG_WOWLAN -DRTW_WAKEUP_EVENT=$(CONFIG_WAKEUP_TYPE) -+EXTRA_CFLAGS += -DRTW_SUSPEND_TYPE=$(CONFIG_SUSPEND_TYPE) -+ifeq ($(CONFIG_WOW_STA_MIX), y) -+EXTRA_CFLAGS += -DRTW_WOW_STA_MIX -+endif -+ifeq ($(CONFIG_SDIO_HCI), y) -+EXTRA_CFLAGS += -DCONFIG_RTW_SDIO_PM_KEEP_POWER -+endif -+endif -+ -+ifeq ($(CONFIG_AP_WOWLAN), y) -+EXTRA_CFLAGS += -DCONFIG_AP_WOWLAN -+ifeq ($(CONFIG_SDIO_HCI), y) -+EXTRA_CFLAGS += -DCONFIG_RTW_SDIO_PM_KEEP_POWER -+endif -+endif -+ -+ifeq ($(CONFIG_PNO_SUPPORT), y) -+EXTRA_CFLAGS += -DCONFIG_PNO_SUPPORT -+ifeq ($(CONFIG_PNO_SET_DEBUG), y) -+EXTRA_CFLAGS += -DCONFIG_PNO_SET_DEBUG -+endif -+endif -+ -+ifeq ($(CONFIG_GPIO_WAKEUP), y) -+EXTRA_CFLAGS += -DCONFIG_GPIO_WAKEUP -+ifeq ($(CONFIG_ONE_PIN_GPIO), y) -+EXTRA_CFLAGS += -DCONFIG_RTW_ONE_PIN_GPIO -+endif -+ifeq ($(CONFIG_HIGH_ACTIVE_DEV2HST), y) -+EXTRA_CFLAGS += -DHIGH_ACTIVE_DEV2HST=1 -+else -+EXTRA_CFLAGS += -DHIGH_ACTIVE_DEV2HST=0 -+endif -+endif -+ -+ifeq ($(CONFIG_HIGH_ACTIVE_HST2DEV), y) -+EXTRA_CFLAGS += -DHIGH_ACTIVE_HST2DEV=1 -+else -+EXTRA_CFLAGS += -DHIGH_ACTIVE_HST2DEV=0 -+endif -+ -+ifneq ($(CONFIG_WAKEUP_GPIO_IDX), default) -+EXTRA_CFLAGS += -DWAKEUP_GPIO_IDX=$(CONFIG_WAKEUP_GPIO_IDX) -+endif -+ -+ifeq ($(CONFIG_RTW_SDIO_PM_KEEP_POWER), y) -+ifeq ($(CONFIG_SDIO_HCI), y) -+EXTRA_CFLAGS += -DCONFIG_RTW_SDIO_PM_KEEP_POWER -+endif -+endif -+ -+ifeq ($(CONFIG_REDUCE_TX_CPU_LOADING), y) -+EXTRA_CFLAGS += -DCONFIG_REDUCE_TX_CPU_LOADING -+endif -+ -+ifeq ($(CONFIG_BR_EXT), y) -+BR_NAME = br0 -+EXTRA_CFLAGS += -DCONFIG_BR_EXT -+EXTRA_CFLAGS += '-DCONFIG_BR_EXT_BRNAME="'$(BR_NAME)'"' -+endif -+ -+ -+ifeq ($(CONFIG_TDLS), y) -+EXTRA_CFLAGS += -DCONFIG_TDLS -+endif -+ -+ifeq ($(CONFIG_WIFI_MONITOR), y) -+EXTRA_CFLAGS += -DCONFIG_WIFI_MONITOR -+endif -+ -+ifeq ($(CONFIG_MCC_MODE), y) -+EXTRA_CFLAGS += -DCONFIG_MCC_MODE -+endif -+ -+ifeq ($(CONFIG_RTW_NAPI), y) -+EXTRA_CFLAGS += -DCONFIG_RTW_NAPI -+endif -+ -+ifeq ($(CONFIG_RTW_GRO), y) -+EXTRA_CFLAGS += -DCONFIG_RTW_GRO -+endif -+ -+ifeq ($(CONFIG_RTW_REPEATER_SON), y) -+EXTRA_CFLAGS += -DCONFIG_RTW_REPEATER_SON -+endif -+ -+ifeq ($(CONFIG_RTW_IPCAM_APPLICATION), y) -+EXTRA_CFLAGS += -DCONFIG_RTW_IPCAM_APPLICATION -+ifeq ($(CONFIG_WIFI_MONITOR), n) -+EXTRA_CFLAGS += -DCONFIG_WIFI_MONITOR -+endif -+endif -+ -+ifeq ($(CONFIG_RTW_NETIF_SG), y) -+EXTRA_CFLAGS += -DCONFIG_RTW_NETIF_SG -+endif -+ -+ifeq ($(CONFIG_TX_CSUM_OFFLOAD), y) -+EXTRA_CFLAGS += -DCONFIG_TX_CSUM_OFFLOAD -+endif -+ -+ifeq ($(CONFIG_ICMP_VOQ), y) -+EXTRA_CFLAGS += -DCONFIG_ICMP_VOQ -+endif -+ -+ifeq ($(CONFIG_IP_R_MONITOR), y) -+EXTRA_CFLAGS += -DCONFIG_IP_R_MONITOR -+endif -+ -+ifeq ($(CONFIG_RTW_WIFI_HAL), y) -+#EXTRA_CFLAGS += -DCONFIG_RTW_WIFI_HAL_DEBUG -+EXTRA_CFLAGS += -DCONFIG_RTW_WIFI_HAL -+EXTRA_CFLAGS += -DCONFIG_RTW_CFGVEDNOR_LLSTATS -+EXTRA_CFLAGS += -DCONFIG_RTW_CFGVENDOR_RANDOM_MAC_OUI -+EXTRA_CFLAGS += -DCONFIG_RTW_CFGVEDNOR_RSSIMONITOR -+EXTRA_CFLAGS += -DCONFIG_RTW_CFGVENDOR_WIFI_LOGGER -+endif -+ -+ifeq ($(CONFIG_MP_VHT_HW_TX_MODE), y) -+EXTRA_CFLAGS += -DCONFIG_MP_VHT_HW_TX_MODE -+ifeq ($(CONFIG_PLATFORM_I386_PC), y) -+## For I386 X86 ToolChain use Hardware FLOATING -+EXTRA_CFLAGS += -mhard-float -+EXTRA_CFLAGS += -DMARK_KERNEL_PFU -+else -+## For ARM ToolChain use Hardware FLOATING -+# Raspbian kernel is with soft-float. -+# 'softfp' allows FP instructions, but no FP on function call interfaces -+EXTRA_CFLAGS += -mfloat-abi=softfp -+endif -+endif -+ -+ifeq ($(CONFIG_APPEND_VENDOR_IE_ENABLE), y) -+EXTRA_CFLAGS += -DCONFIG_APPEND_VENDOR_IE_ENABLE -+endif -+ -+ifeq ($(CONFIG_RTW_DEBUG), y) -+EXTRA_CFLAGS += -DCONFIG_RTW_DEBUG -+EXTRA_CFLAGS += -DRTW_LOG_LEVEL=$(CONFIG_RTW_LOG_LEVEL) -+endif -+ -+EXTRA_CFLAGS += -DDM_ODM_SUPPORT_TYPE=0x04 -+ -+ifeq ($(CONFIG_PLATFORM_I386_PC), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+SUBARCH := $(shell uname -m | sed -e "s/i.86/i386/; s/ppc/powerpc/; s/armv.l/arm/; s/aarch64/arm64/;") -+ARCH ?= $(SUBARCH) -+CROSS_COMPILE ?= -+KVER := $(shell uname -r) -+KSRC := /lib/modules/$(KVER)/build -+MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/ -+INSTALL_PREFIX := -+STAGINGMODDIR := /lib/modules/$(KVER)/kernel/drivers/staging -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ARM_RPI), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+ARCH ?= arm -+CROSS_COMPILE ?= -+KVER ?= $(shell uname -r) -+KSRC := /lib/modules/$(KVER)/build -+MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/ -+INSTALL_PREFIX := -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ARM64_RPI), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+ARCH ?= arm64 -+CROSS_COMPILE ?= -+KVER ?= $(shell uname -r) -+KSRC := /lib/modules/$(KVER)/build -+MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/ -+INSTALL_PREFIX := -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ARM_NV_NANO), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+ARCH := arm64 -+KVER := $(shell uname -r) -+KSRC := /lib/modules/$(KVER)/build -+MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/ -+INSTALL_PREFIX := -+STAGINGMODDIR := /lib/modules/$(KVER)/kernel/drivers/staging -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ARM_ODROIDC2), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+ARCH ?= arm64 -+CROSS_COMPILE ?= -+KVER ?= $(shell uname -r) -+KSRC := /lib/modules/$(KVER)/build -+MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/ -+INSTALL_PREFIX := -+endif -+ -+ifeq ($(CONFIG_PLATFORM_PPC), y) -+EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN -+SUBARCH := $(shell uname -m | sed -e s/ppc/powerpc/) -+ARCH ?= $(SUBARCH) -+CROSS_COMPILE ?= -+KVER ?= $(shell uname -r) -+KSRC := /lib/modules/$(KVER)/build -+MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/ -+INSTALL_PREFIX := -+endif -+ -+ifeq ($(CONFIG_PLATFORM_NV_TK1), y) -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_NV_TK1 -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+# default setting for Android 4.1, 4.2 -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE -+EXTRA_CFLAGS += -DCONFIG_P2P_IPS -DCONFIG_PLATFORM_ANDROID -+# Enable this for Android 5.0 -+EXTRA_CFLAGS += -DCONFIG_RADIO_WORK -+EXTRA_CFLAGS += -DRTW_VENDOR_EXT_SUPPORT -+EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC -+ARCH ?= arm -+ -+CROSS_COMPILE := /mnt/newdisk/android_sdk/nvidia_tk1/android_L/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi- -+KSRC :=/mnt/newdisk/android_sdk/nvidia_tk1/android_L/out/target/product/shieldtablet/obj/KERNEL/ -+MODULE_NAME = wlan -+endif -+ -+ifeq ($(CONFIG_PLATFORM_NV_TK1_UBUNTU), y) -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_NV_TK1 -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+ -+ARCH ?= arm -+ -+CROSS_COMPILE ?= -+KVER := $(shell uname -r) -+KSRC := /lib/modules/$(KVER)/build -+MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/ -+INSTALL_PREFIX := -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ACTIONS_ATM702X), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -DCONFIG_PLATFORM_ACTIONS_ATM702X -+#ARCH := arm -+ARCH := $(R_ARCH) -+#CROSS_COMPILE := arm-none-linux-gnueabi- -+CROSS_COMPILE := $(R_CROSS_COMPILE) -+KVER:= 3.4.0 -+#KSRC := ../../../../build/out/kernel -+KSRC := $(KERNEL_BUILD_PATH) -+MODULE_NAME :=wlan -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ACTIONS_ATM705X), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+#EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC -+# default setting for Android 4.1, 4.2, 4.3, 4.4 -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ACTIONS_ATM705X -+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+ -+# Enable this for Android 5.0 -+EXTRA_CFLAGS += -DCONFIG_RADIO_WORK -+ -+ifeq ($(CONFIG_SDIO_HCI), y) -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS -+_PLATFORM_FILES += platform/platform_arm_act_sdio.o -+endif -+ -+ARCH := arm -+CROSS_COMPILE := /opt/arm-2011.09/bin/arm-none-linux-gnueabi- -+KSRC := /home/android_sdk/Action-semi/705a_android_L/android/kernel -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ARM_SUN50IW1P1), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN50IW1P1 -+EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT -+# default setting for Android 4.1, 4.2 -+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+EXTRA_CFLAGS += -DCONFIG_RESUME_IN_WORKQUEUE -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS -+ -+# Enable this for Android 5.0 -+EXTRA_CFLAGS += -DCONFIG_RADIO_WORK -+ -+ifeq ($(CONFIG_USB_HCI), y) -+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX -+_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o -+endif -+ifeq ($(CONFIG_SDIO_HCI), y) -+_PLATFORM_FILES += platform/platform_ARM_SUN50IW1P1_sdio.o -+endif -+ -+ARCH := arm64 -+# ===Cross compile setting for Android 5.1(64) SDK === -+CROSS_COMPILE := /home/android_sdk/Allwinner/a64/android-51/lichee/out/sun50iw1p1/android/common/buildroot/external-toolchain/bin/aarch64-linux-gnu- -+KSRC :=/home/android_sdk/Allwinner/a64/android-51/lichee/linux-3.10/ -+endif -+ -+ifeq ($(CONFIG_PLATFORM_TI_AM3517), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -DCONFIG_PLATFORM_SHUTTLE -+CROSS_COMPILE := arm-eabi- -+KSRC := $(shell pwd)/../../../Android/kernel -+ARCH := arm -+endif -+ -+ifeq ($(CONFIG_PLATFORM_MSTAR_TITANIA12), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MSTAR -DCONFIG_PLATFORM_MSTAR_TITANIA12 -+ARCH:=mips -+CROSS_COMPILE:= /usr/src/Mstar_kernel/mips-4.3/bin/mips-linux-gnu- -+KVER:= 2.6.28.9 -+KSRC:= /usr/src/Mstar_kernel/2.6.28.9/ -+endif -+ -+ifeq ($(CONFIG_PLATFORM_MSTAR), y) -+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_MSTAR -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_MSTAR_HIGH -+ifeq ($(CONFIG_USB_HCI), y) -+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX -DCONFIG_FIX_NR_BULKIN_BUFFER -+endif -+ARCH:=arm -+CROSS_COMPILE:= /usr/src/bin/arm-none-linux-gnueabi- -+KVER:= 3.1.10 -+KSRC:= /usr/src/Mstar_kernel/3.1.10/ -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ANDROID_ARM64), y) -+# For this to work, change the "modules:" section is also needed, in order to build with CLANG. -+# "$(MAKE) ARCH=$(ARCH) SUBARCH=$(ARCH) REAL_CC=${CC_DIR}/clang CLANG_TRIPLE=aarch64-linux-gnu- CROSS_COMPILE=$(CROSS_COMPILE) -C $(KSRC) M=$(shell pwd) O="$(KBUILD_OUTPUT)" modules" -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -fno-pic -+EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC -DCONFIG_RADIO_WORK -+#Enable this to have two interfaces: -+#EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+EXTRA_CFLAGS += -DCONFIG_P2P_IPS -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ANDROID_X86), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+SUBARCH := $(shell uname -m | sed -e s/i.86/i386/) -+ARCH := $(SUBARCH) -+CROSS_COMPILE := /media/DATA-2/android-x86/ics-x86_20120130/prebuilt/linux-x86/toolchain/i686-unknown-linux-gnu-4.2.1/bin/i686-unknown-linux-gnu- -+KSRC := /media/DATA-2/android-x86/ics-x86_20120130/out/target/product/generic_x86/obj/kernel -+MODULE_NAME :=wlan -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ANDROID_INTEL_X86), y) -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ANDROID_INTEL_X86 -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_INTEL_BYT -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+EXTRA_CFLAGS += -DCONFIG_SKIP_SIGNAL_SCALE_MAPPING -+ifeq ($(CONFIG_SDIO_HCI), y) -+EXTRA_CFLAGS += -DCONFIG_RESUME_IN_WORKQUEUE -+endif -+endif -+ -+ifeq ($(CONFIG_PLATFORM_JB_X86), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+SUBARCH := $(shell uname -m | sed -e s/i.86/i386/) -+ARCH := $(SUBARCH) -+CROSS_COMPILE := /home/android_sdk/android-x86_JB/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7/bin/i686-linux-android- -+KSRC := /home/android_sdk/android-x86_JB/out/target/product/x86/obj/kernel/ -+MODULE_NAME :=wlan -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ARM_PXA2XX), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+ARCH := arm -+CROSS_COMPILE := arm-none-linux-gnueabi- -+KVER := 2.6.34.1 -+KSRC ?= /usr/src/linux-2.6.34.1 -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ARM_S3C2K4), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+ARCH := arm -+CROSS_COMPILE := arm-linux- -+KVER := 2.6.24.7_$(ARCH) -+KSRC := /usr/src/kernels/linux-$(KVER) -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ARM_S3C6K4), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+ARCH := arm -+CROSS_COMPILE := arm-none-linux-gnueabi- -+KVER := 2.6.34.1 -+KSRC ?= /usr/src/linux-2.6.34.1 -+endif -+ -+ifeq ($(CONFIG_PLATFORM_RTD2880B), y) -+EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN -DCONFIG_PLATFORM_RTD2880B -+ARCH:= -+CROSS_COMPILE:= -+KVER:= -+KSRC:= -+endif -+ -+ifeq ($(CONFIG_PLATFORM_MIPS_RMI), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+ARCH:=mips -+CROSS_COMPILE:=mipsisa32r2-uclibc- -+KVER:= -+KSRC:= /root/work/kernel_realtek -+endif -+ -+ifeq ($(CONFIG_PLATFORM_MIPS_PLM), y) -+EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN -+ARCH:=mips -+CROSS_COMPILE:=mipsisa32r2-uclibc- -+KVER:= -+KSRC:= /root/work/kernel_realtek -+endif -+ -+ifeq ($(CONFIG_PLATFORM_MSTAR389), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MSTAR389 -+ARCH:=mips -+CROSS_COMPILE:= mips-linux-gnu- -+KVER:= 2.6.28.10 -+KSRC:= /home/mstar/mstar_linux/2.6.28.9/ -+endif -+ -+ifeq ($(CONFIG_PLATFORM_MIPS_AR9132), y) -+EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN -+ARCH := mips -+CROSS_COMPILE := mips-openwrt-linux- -+KSRC := /home/alex/test_openwrt/tmp/linux-2.6.30.9 -+endif -+ -+# This is how I built for openwrt Neo2 platform. --Ben -+ifeq ($(CONFIG_PLATFORM_OPENWRT_NEO2), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+ARCH := arm64 -+CROSS_COMPILE := aarch64-openwrt-linux- -+#export PATH=$PATH:/home/greearb/git/openwrt-neo2-dev/staging_dir/toolchain-aarch64_cortex-a53_gcc-7.3.0_musl/bin/ -+#export STAGING_DIR=/home/greearb/git/openwrt-neo2-dev/staging_dir -+KSRC := /home/greearb/git/openwrt-neo2-dev/build_dir/target-aarch64_cortex-a53_musl/linux-sunxi_cortexa53/linux-4.14.78 -+endif -+ -+ifeq ($(CONFIG_PLATFORM_DMP_PHILIPS), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DRTK_DMP_PLATFORM -+ARCH := mips -+#CROSS_COMPILE:=/usr/local/msdk-4.3.6-mips-EL-2.6.12.6-0.9.30.3/bin/mipsel-linux- -+CROSS_COMPILE:=/usr/local/toolchain_mipsel/bin/mipsel-linux- -+KSRC ?=/usr/local/Jupiter/linux-2.6.12 -+endif -+ -+ifeq ($(CONFIG_PLATFORM_RTK_DMP), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DRTK_DMP_PLATFORM -DCONFIG_WIRELESS_EXT -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS -+ifeq ($(CONFIG_USB_HCI), y) -+_PLATFORM_FILES += platform/platform_RTK_DMP_usb.o -+endif -+ARCH:=mips -+CROSS_COMPILE:=mipsel-linux- -+KVER:= -+KSRC ?= /usr/src/DMP_Kernel/jupiter/linux-2.6.12 -+endif -+ -+ifeq ($(CONFIG_PLATFORM_MT53XX), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MT53XX -+ARCH:= arm -+CROSS_COMPILE:= arm11_mtk_le- -+KVER:= 2.6.27 -+KSRC?= /proj/mtk00802/BD_Compare/BDP/Dev/BDP_V301/BDP_Linux/linux-2.6.27 -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ARM_MX51_241H), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_WISTRON_PLATFORM -+ARCH := arm -+CROSS_COMPILE := /opt/freescale/usr/local/gcc-4.1.2-glibc-2.5-nptl-3/arm-none-linux-gnueabi/bin/arm-none-linux-gnueabi- -+KVER := 2.6.31 -+KSRC ?= /lib/modules/2.6.31-770-g0e46b52/source -+endif -+ -+ifeq ($(CONFIG_PLATFORM_FS_MX61), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+ARCH := arm -+CROSS_COMPILE ?= -+KVER ?= $(shell uname -r) -+KSRC := /lib/modules/$(KVER)/build -+MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/ -+INSTALL_PREFIX := -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ACTIONS_ATJ227X), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ACTIONS_ATJ227X -+ARCH := mips -+CROSS_COMPILE := /home/cnsd4/project/actions/tools-2.6.27/bin/mipsel-linux-gnu- -+KVER := 2.6.27 -+KSRC := /home/cnsd4/project/actions/linux-2.6.27.28 -+endif -+ -+ifeq ($(CONFIG_PLATFORM_TI_DM365), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_TI_DM365 -+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_RX -+EXTRA_CFLAGS += -DCONFIG_SINGLE_XMIT_BUF -DCONFIG_SINGLE_RECV_BUF -+ARCH := arm -+#CROSS_COMPILE := /home/cnsd4/Appro/mv_pro_5.0/montavista/pro/devkit/arm/v5t_le/bin/arm_v5t_le- -+#KSRC := /home/cnsd4/Appro/mv_pro_5.0/montavista/pro/devkit/lsp/ti-davinci/linux-dm365 -+CROSS_COMPILE := /opt/montavista/pro5.0/devkit/arm/v5t_le/bin/arm-linux- -+KSRC:= /home/vivotek/lsp/DM365/kernel_platform/kernel/linux-2.6.18 -+KERNELOUTPUT := ${PRODUCTDIR}/tmp -+KVER := 2.6.18 -+endif -+ -+ifeq ($(CONFIG_PLATFORM_MOZART), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MOZART -+ARCH := arm -+CROSS_COMPILE := /home/vivotek/lsp/mozart3v2/Mozart3e_Toolchain/build_arm_nofpu/usr/bin/arm-linux- -+KVER := $(shell uname -r) -+KSRC:= /opt/Vivotek/lsp/mozart3v2/kernel_platform/kernel/mozart_kernel-1.17 -+KERNELOUTPUT := /home/pink/sample/ODM/IP8136W-VINT/tmp/kernel -+endif -+ -+ifeq ($(CONFIG_PLATFORM_TEGRA3_CARDHU), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+# default setting for Android 4.1, 4.2 -+EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC -+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+ARCH := arm -+CROSS_COMPILE := /home/android_sdk/nvidia/tegra-16r3-partner-android-4.1_20120723/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi- -+KSRC := /home/android_sdk/nvidia/tegra-16r3-partner-android-4.1_20120723/out/target/product/cardhu/obj/KERNEL -+MODULE_NAME := wlan -+endif -+ -+ifeq ($(CONFIG_PLATFORM_TEGRA4_DALMORE), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+# default setting for Android 4.1, 4.2 -+EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC -+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+ARCH := arm -+CROSS_COMPILE := /home/android_sdk/nvidia/tegra-17r9-partner-android-4.2-dalmore_20130131/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi- -+KSRC := /home/android_sdk/nvidia/tegra-17r9-partner-android-4.2-dalmore_20130131/out/target/product/dalmore/obj/KERNEL -+MODULE_NAME := wlan -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ARM_TCC8900), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+ARCH := arm -+CROSS_COMPILE := /home/android_sdk/Telechips/SDK_2304_20110613/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi- -+KSRC := /home/android_sdk/Telechips/SDK_2304_20110613/kernel -+MODULE_NAME := wlan -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ARM_TCC8920), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+ARCH := arm -+CROSS_COMPILE := /home/android_sdk/Telechips/v12.06_r1-tcc-android-4.0.4/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi- -+KSRC := /home/android_sdk/Telechips/v12.06_r1-tcc-android-4.0.4/kernel -+MODULE_NAME := wlan -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ARM_TCC8920_JB42), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+# default setting for Android 4.1, 4.2 -+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+ARCH := arm -+CROSS_COMPILE := /home/android_sdk/Telechips/v13.03_r1-tcc-android-4.2.2_ds_patched/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi- -+KSRC := /home/android_sdk/Telechips/v13.03_r1-tcc-android-4.2.2_ds_patched/kernel -+MODULE_NAME := wlan -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ARM_RK2818), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -DCONFIG_PLATFORM_ROCKCHIPS -+ARCH := arm -+CROSS_COMPILE := /usr/src/release_fae_version/toolchain/arm-eabi-4.4.0/bin/arm-eabi- -+KSRC := /usr/src/release_fae_version/kernel25_A7_281x -+MODULE_NAME := wlan -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ARM_RK3188), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -DCONFIG_PLATFORM_ROCKCHIPS -+# default setting for Android 4.1, 4.2, 4.3, 4.4 -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE -+# default setting for Power control -+EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC -+EXTRA_CFLAGS += -DRTW_SUPPORT_PLATFORM_SHUTDOWN -+# default setting for Special function -+ARCH := arm -+CROSS_COMPILE := /home/android_sdk/Rockchip/Rk3188/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi- -+KSRC := /home/android_sdk/Rockchip/Rk3188/kernel -+MODULE_NAME := wlan -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ARM_RK3066), y) -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_RK3066 -+EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -+ifeq ($(CONFIG_SDIO_HCI), y) -+EXTRA_CFLAGS += -DRTW_SUPPORT_PLATFORM_SHUTDOWN -+endif -+EXTRA_CFLAGS += -fno-pic -+ARCH := arm -+CROSS_COMPILE := /home/android_sdk/Rockchip/rk3066_20130607/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.6/bin/arm-linux-androideabi- -+#CROSS_COMPILE := /home/android_sdk/Rockchip/Rk3066sdk/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.6/bin/arm-linux-androideabi- -+KSRC := /home/android_sdk/Rockchip/Rk3066sdk/kernel -+MODULE_NAME :=wlan -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ARM_URBETTER), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN #-DCONFIG_MINIMAL_MEMORY_USAGE -+ARCH := arm -+CROSS_COMPILE := /media/DATA-1/urbetter/arm-2009q3/bin/arm-none-linux-gnueabi- -+KSRC := /media/DATA-1/urbetter/ics-urbetter/kernel -+MODULE_NAME := wlan -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ARM_TI_PANDA), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN #-DCONFIG_MINIMAL_MEMORY_USAGE -+ARCH := arm -+#CROSS_COMPILE := /media/DATA-1/aosp/ics-aosp_20111227/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi- -+#KSRC := /media/DATA-1/aosp/android-omap-panda-3.0_20120104 -+CROSS_COMPILE := /media/DATA-1/android-4.0/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi- -+KSRC := /media/DATA-1/android-4.0/panda_kernel/omap -+MODULE_NAME := wlan -+endif -+ -+ifeq ($(CONFIG_PLATFORM_MIPS_JZ4760), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_MINIMAL_MEMORY_USAGE -+ARCH ?= mips -+CROSS_COMPILE ?= /mnt/sdb5/Ingenic/Umido/mips-4.3/bin/mips-linux-gnu- -+KSRC ?= /mnt/sdb5/Ingenic/Umido/kernel -+endif -+ -+ifeq ($(CONFIG_PLATFORM_SZEBOOK), y) -+EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN -+ARCH:=arm -+CROSS_COMPILE:=/opt/crosstool2/bin/armeb-unknown-linux-gnueabi- -+KVER:= 2.6.31.6 -+KSRC:= ../code/linux-2.6.31.6-2020/ -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ARM_SUNxI), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUNxI -+# default setting for Android 4.1, 4.2 -+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+ -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS -+ifeq ($(CONFIG_USB_HCI), y) -+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX -+_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o -+endif -+ifeq ($(CONFIG_SDIO_HCI), y) -+# default setting for A10-EVB mmc0 -+#EXTRA_CFLAGS += -DCONFIG_WITS_EVB_V13 -+_PLATFORM_FILES += platform/platform_ARM_SUNxI_sdio.o -+endif -+ -+ARCH := arm -+#CROSS_COMPILE := arm-none-linux-gnueabi- -+CROSS_COMPILE=/home/android_sdk/Allwinner/a10/android-jb42/lichee-jb42/buildroot/output/external-toolchain/bin/arm-none-linux-gnueabi- -+KVER := 3.0.8 -+#KSRC:= ../lichee/linux-3.0/ -+KSRC=/home/android_sdk/Allwinner/a10/android-jb42/lichee-jb42/linux-3.0 -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ARM_SUN6I), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN6I -+EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT -+# default setting for Android 4.1, 4.2, 4.3, 4.4 -+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+EXTRA_CFLAGS += -DCONFIG_QOS_OPTIMIZATION -+ -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS -+ifeq ($(CONFIG_USB_HCI), y) -+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX -+_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o -+endif -+ifeq ($(CONFIG_SDIO_HCI), y) -+# default setting for A31-EVB mmc0 -+EXTRA_CFLAGS += -DCONFIG_A31_EVB -+_PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o -+endif -+ -+ARCH := arm -+#Android-JB42 -+#CROSS_COMPILE := /home/android_sdk/Allwinner/a31/android-jb42/lichee/buildroot/output/external-toolchain/bin/arm-linux-gnueabi- -+#KSRC :=/home/android_sdk/Allwinner/a31/android-jb42/lichee/linux-3.3 -+#ifeq ($(CONFIG_USB_HCI), y) -+#MODULE_NAME := 8188eu_sw -+#endif -+# ==== Cross compile setting for kitkat-a3x_v4.5 ===== -+CROSS_COMPILE := /home/android_sdk/Allwinner/a31/kitkat-a3x_v4.5/lichee/buildroot/output/external-toolchain/bin/arm-linux-gnueabi- -+KSRC :=/home/android_sdk/Allwinner/a31/kitkat-a3x_v4.5/lichee/linux-3.3 -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ARM_SUN7I), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN7I -+EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT -+# default setting for Android 4.1, 4.2, 4.3, 4.4 -+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+EXTRA_CFLAGS += -DCONFIG_QOS_OPTIMIZATION -+ -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS -+ifeq ($(CONFIG_USB_HCI), y) -+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX -+_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o -+endif -+ifeq ($(CONFIG_SDIO_HCI), y) -+_PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o -+endif -+ -+ARCH := arm -+# ===Cross compile setting for Android 4.2 SDK === -+#CROSS_COMPILE := /home/android_sdk/Allwinner/a20_evb/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi- -+#KSRC := /home/android_sdk/Allwinner/a20_evb/lichee/linux-3.3 -+# ==== Cross compile setting for Android 4.3 SDK ===== -+#CROSS_COMPILE := /home/android_sdk/Allwinner/a20/android-jb43/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi- -+#KSRC := /home/android_sdk/Allwinner/a20/android-jb43/lichee/linux-3.4 -+# ==== Cross compile setting for kitkat-a20_v4.4 ===== -+CROSS_COMPILE := /home/android_sdk/Allwinner/a20/kitkat-a20_v4.4/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi- -+KSRC := /home/android_sdk/Allwinner/a20/kitkat-a20_v4.4/lichee/linux-3.4 -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ARM_SUN8I_W3P1), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN8I -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN8I_W3P1 -+EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT -+# default setting for Android 4.1, 4.2 -+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+ -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS -+ifeq ($(CONFIG_USB_HCI), y) -+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX -+_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o -+endif -+ifeq ($(CONFIG_SDIO_HCI), y) -+_PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o -+endif -+ -+ARCH := arm -+# ===Cross compile setting for Android 4.2 SDK === -+#CROSS_COMPILE := /home/android_sdk/Allwinner/a23/android-jb42/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi- -+#KSRC :=/home/android_sdk/Allwinner/a23/android-jb42/lichee/linux-3.4 -+# ===Cross compile setting for Android 4.4 SDK === -+CROSS_COMPILE := /home/android_sdk/Allwinner/a23/android-kk44/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi- -+KSRC :=/home/android_sdk/Allwinner/a23/android-kk44/lichee/linux-3.4 -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ARM_SUN8I_W5P1), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN8I -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN8I_W5P1 -+EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT -+# default setting for Android 4.1, 4.2 -+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+ -+# Enable this for Android 5.0 -+EXTRA_CFLAGS += -DCONFIG_RADIO_WORK -+ -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS -+ifeq ($(CONFIG_USB_HCI), y) -+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX -+_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o -+endif -+ifeq ($(CONFIG_SDIO_HCI), y) -+_PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o -+endif -+ -+ARCH := arm -+# ===Cross compile setting for Android L SDK === -+CROSS_COMPILE := /home/android_sdk/Allwinner/a33/android-L/lichee/out/sun8iw5p1/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi- -+KSRC :=/home/android_sdk/Allwinner/a33/android-L/lichee/linux-3.4 -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ACTIONS_ATV5201), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ACTIONS_ATV5201 -+EXTRA_CFLAGS += -DCONFIG_SDIO_DISABLE_RXFIFO_POLLING_LOOP -+ARCH := mips -+CROSS_COMPILE := mipsel-linux-gnu- -+KVER := $(KERNEL_VER) -+KSRC:= $(CFGDIR)/../../kernel/linux-$(KERNEL_VER) -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ARM_RTD299X), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+ifeq ($(CONFIG_ANDROID), y) -+# Enable this for Android 5.0 -+EXTRA_CFLAGS += -DCONFIG_RADIO_WORK -+endif -+#ARCH, CROSS_COMPILE, KSRC,and MODDESTDIR are provided by external makefile -+INSTALL_PREFIX := -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ARM_RTD299X_LG), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE -+EXTRA_CFLAGS += -DRTW_P2P_GROUP_INTERFACE=1 -+EXTRA_CFLAGS += -DCONFIG_IFACE_NUMBER=3 -+#EXTRA_CFLAGS += -DCONFIG_FIX_HWPORT -+EXTRA_CFLAGS += -DLGE_PRIVATE -+EXTRA_CFLAGS += -DPURE_SUPPLICANT -+EXTRA_CFLAGS += -DCONFIG_CUSTOMIZED_COUNTRY_CHPLAN_MAP -DCONFIG_RTW_IOCTL_SET_COUNTRY -+EXTRA_CFLAGS += -DDBG_RX_DFRAME_RAW_DATA -+EXTRA_CFLAGS += -DRTW_REDUCE_SCAN_SWITCH_CH_TIME -+ARCH ?= arm -+KVER ?= -+ -+ifneq ($(PLATFORM), WEBOS) -+$(info PLATFORM is empty) -+CROSS_COMPILE ?= /mnt/newdisk/LGE/arm-lg115x-linux-gnueabi-4.8-2016.03-x86_64/bin/arm-lg115x-linux-gnueabi- -+KSRC ?= /mnt/newdisk/LGE/linux-rockhopper_k3lp_drd4tv_423 -+endif -+ -+CROSS_COMPILE ?= -+KSRC ?= $(LINUX_SRC) -+INSTALL_PREFIX ?= -+endif -+ -+ifeq ($(CONFIG_PLATFORM_HISILICON), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_HISILICON -+ifeq ($(SUPPORT_CONCURRENT),y) -+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE -+endif -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+ARCH := arm -+ifeq ($(CROSS_COMPILE),) -+ CROSS_COMPILE = arm-hisiv200-linux- -+endif -+MODULE_NAME := rtl8192eu -+ifeq ($(KSRC),) -+ KSRC := ../../../../../../kernel/linux-3.4.y -+endif -+endif -+ -+ifeq ($(CONFIG_PLATFORM_HISILICON_HI3798), y) -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_HISILICON -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_HISILICON_HI3798 -+#EXTRA_CFLAGS += -DCONFIG_PLATFORM_HISILICON_HI3798_MV200_HDMI_DONGLE -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+# default setting for Android -+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -+EXTRA_CFLAGS += -DRTW_USE_CFG80211_STA_EVENT -+# default setting for Android 5.x and later -+#EXTRA_CFLAGS += -DCONFIG_RADIO_WORK -+ -+# If system could power on and recognize Wi-Fi SDIO automatically, -+# platfrom operations are not necessary. -+#ifeq ($(CONFIG_SDIO_HCI), y) -+#EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS -+#_PLATFORM_FILES += platform/platform_hisilicon_hi3798_sdio.o -+#EXTRA_CFLAGS += -DCONFIG_HISI_SDIO_ID=1 -+#endif -+ -+ARCH ?= arm -+CROSS_COMPILE ?= /HiSTBAndroidV600R003C00SPC021_git_0512/device/hisilicon/bigfish/sdk/tools/linux/toolchains/arm-histbv310-linux/bin/arm-histbv310-linux- -+ifndef KSRC -+KSRC := /HiSTBAndroidV600R003C00SPC021_git_0512/device/hisilicon/bigfish/sdk/source/kernel/linux-3.18.y -+KSRC += O=/HiSTBAndroidV600R003C00SPC021_git_0512/out/target/product/Hi3798MV200/obj/KERNEL_OBJ -+endif -+ -+ifeq ($(CONFIG_RTL8822B), y) -+ifeq ($(CONFIG_SDIO_HCI), y) -+CONFIG_RTL8822BS ?= m -+USER_MODULE_NAME := rtl8822bs -+endif -+endif -+ -+endif -+ -+# Platform setting -+ifeq ($(CONFIG_PLATFORM_ARM_SPREADTRUM_6820), y) -+ifeq ($(CONFIG_ANDROID_2X), y) -+EXTRA_CFLAGS += -DANDROID_2X -+endif -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_SPRD -+EXTRA_CFLAGS += -DPLATFORM_SPREADTRUM_6820 -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+ifeq ($(RTL871X), rtl8188e) -+EXTRA_CFLAGS += -DSOFTAP_PS_DURATION=50 -+endif -+ifeq ($(CONFIG_SDIO_HCI), y) -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS -+_PLATFORM_FILES += platform/platform_sprd_sdio.o -+endif -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ARM_SPREADTRUM_8810), y) -+ifeq ($(CONFIG_ANDROID_2X), y) -+EXTRA_CFLAGS += -DANDROID_2X -+endif -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_SPRD -+EXTRA_CFLAGS += -DPLATFORM_SPREADTRUM_8810 -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+ifeq ($(RTL871X), rtl8188e) -+EXTRA_CFLAGS += -DSOFTAP_PS_DURATION=50 -+endif -+ifeq ($(CONFIG_SDIO_HCI), y) -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS -+_PLATFORM_FILES += platform/platform_sprd_sdio.o -+endif -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ARM_WMT), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS -+ifeq ($(CONFIG_SDIO_HCI), y) -+_PLATFORM_FILES += platform/platform_ARM_WMT_sdio.o -+endif -+ARCH := arm -+CROSS_COMPILE := /home/android_sdk/WonderMedia/wm8880-android4.4/toolchain/arm_201103_gcc4.5.2/mybin/arm_1103_le- -+KSRC := /home/android_sdk/WonderMedia/wm8880-android4.4/kernel4.4/ -+MODULE_NAME :=8189es_kk -+endif -+ -+ifeq ($(CONFIG_PLATFORM_RTK119X), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+#EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN7I -+EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT -+# default setting for Android 4.1, 4.2 -+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+#EXTRA_CFLAGS += -DCONFIG_QOS_OPTIMIZATION -+EXTRA_CFLAGS += -DCONFIG_QOS_OPTIMIZATION -+ -+#EXTRA_CFLAGS += -DCONFIG_#PLATFORM_OPS -+ifeq ($(CONFIG_USB_HCI), y) -+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX -+#_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o -+endif -+ifeq ($(CONFIG_SDIO_HCI), y) -+_PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o -+endif -+ -+ARCH := arm -+ -+# ==== Cross compile setting for Android 4.4 SDK ===== -+#CROSS_COMPILE := arm-linux-gnueabihf- -+KVER := 3.10.24 -+#KSRC :=/home/android_sdk/Allwinner/a20/android-kitkat44/lichee/linux-3.4 -+CROSS_COMPILE := /home/realtek/software_phoenix/phoenix/toolchain/usr/local/arm-2013.11/bin/arm-linux-gnueabihf- -+KSRC := /home/realtek/software_phoenix/linux-kernel -+MODULE_NAME := 8192eu -+ -+endif -+ -+ifeq ($(CONFIG_PLATFORM_RTK119X_AM), y) -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_RTK119X_AM -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT -+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE -DCONFIG_FULL_CH_IN_P2P_HANDSHAKE -+EXTRA_CFLAGS += -DCONFIG_IFACE_NUMBER=3 -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+ -+ifeq ($(CONFIG_USB_HCI), y) -+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX -+endif -+ -+ARCH := arm -+ -+#CROSS_COMPILE := arm-linux-gnueabihf- -+KVER := 3.10.24 -+#KSRC := -+CROSS_COMPILE := -+endif -+ -+ifeq ($(CONFIG_PLATFORM_RTK129X), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+EXTRA_CFLAGS += -DRTK_129X_PLATFORM -+EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT -+# default setting for Android 4.1, 4.2 -+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+#EXTRA_CFLAGS += -DCONFIG_P2P_IPS -DCONFIG_QOS_OPTIMIZATION -+EXTRA_CFLAGS += -DCONFIG_QOS_OPTIMIZATION -+# Enable this for Android 5.0 -+EXTRA_CFLAGS += -DCONFIG_RADIO_WORK -+ifeq ($(CONFIG_RTL8821C)$(CONFIG_SDIO_HCI),yy) -+EXTRA_CFLAGS += -DCONFIG_WAKEUP_GPIO_INPUT_MODE -+EXTRA_CFLAGS += -DCONFIG_BT_WAKE_HST_OPEN_DRAIN -+endif -+EXTRA_CFLAGS += -Wno-error=date-time -+# default setting for Android 7.0 -+ifeq ($(RTK_ANDROID_VERSION), nougat) -+EXTRA_CFLAGS += -DRTW_P2P_GROUP_INTERFACE=1 -+endif -+#EXTRA_CFLAGS += -DCONFIG_#PLATFORM_OPS -+ifeq ($(CONFIG_USB_HCI), y) -+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX -+endif -+ -+ARCH := arm64 -+ -+# ==== Cross compile setting for Android 4.4 SDK ===== -+#CROSS_COMPILE := arm-linux-gnueabihf- -+#KVER := 4.1.10 -+#CROSS_COMPILE := $(CROSS) -+#KSRC := $(LINUX_KERNEL_PATH) -+CROSS_COMPILE := /home/android_sdk/DHC/trunk-6.0.0_r1-QA160627/phoenix/toolchain/asdk64-4.9.4-a53-EL-3.10-g2.19-a64nt-160307/bin/asdk64-linux- -+KSRC := /home/android_sdk/DHC/trunk-6.0.0_r1-QA160627/linux-kernel -+endif -+ -+ifeq ($(CONFIG_PLATFORM_RTK390X), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_RTK390X -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+EXTRA_CFLAGS += -DCONFIG_RTW_NETIF_SG -+ifeq ($(CONFIG_USB_HCI), y) -+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX -+endif -+ -+ARCH:=rlx -+ -+CROSS_COMPILE:=mips-linux- -+KSRC:= /home/realtek/share/Develop/IPCAM_SDK/RealSil/rts3901_sdk_v1.2_vanilla/linux-3.10 -+ -+endif -+ -+ifeq ($(CONFIG_PLATFORM_NOVATEK_NT72668), y) -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_NOVATEK_NT72668 -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_RX -+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX -+ARCH ?= arm -+CROSS_COMPILE := arm-linux-gnueabihf- -+KVER := 3.8.0 -+KSRC := /Custom/Novatek/TCL/linux-3.8_header -+#KSRC := $(KERNELDIR) -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ARM_TCC8930_JB42), y) -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+# default setting for Android 4.1, 4.2 -+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -+ARCH := arm -+CROSS_COMPILE := /home/android_sdk/Telechips/v13.05_r1-tcc-android-4.2.2_tcc893x-evm_build/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi- -+KSRC := /home/android_sdk/Telechips/v13.05_r1-tcc-android-4.2.2_tcc893x-evm_build/kernel -+MODULE_NAME := wlan -+endif -+ -+ifeq ($(CONFIG_PLATFORM_RTL8197D), y) -+EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN -DCONFIG_PLATFORM_RTL8197D -+export DIR_LINUX=$(shell pwd)/../SDK/rlxlinux-sdk321-v50/linux-2.6.30 -+ARCH ?= rlx -+CROSS_COMPILE:= $(DIR_LINUX)/../toolchain/rsdk-1.5.5-5281-EB-2.6.30-0.9.30.3-110714/bin/rsdk-linux- -+KSRC := $(DIR_LINUX) -+endif -+ -+ifeq ($(CONFIG_PLATFORM_AML_S905), y) -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_AML_S905 -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -fno-pic -+# default setting for Android -+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -+EXTRA_CFLAGS += -DRTW_USE_CFG80211_STA_EVENT -+# default setting for Android 5.x and later -+EXTRA_CFLAGS += -DCONFIG_RADIO_WORK -+ -+ifeq ($(CONFIG_SDIO_HCI), y) -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS -+_PLATFORM_FILES += platform/platform_aml_s905_sdio.o -+endif -+ -+ARCH ?= arm64 -+CROSS_COMPILE ?= /4.4_S905L_8822bs_compile/gcc-linaro-aarch64-linux-gnu-4.9-2014.09_linux/bin/aarch64-linux-gnu- -+ifndef KSRC -+KSRC := /4.4_S905L_8822bs_compile/common -+# To locate output files in a separate directory. -+KSRC += O=/4.4_S905L_8822bs_compile/KERNEL_OBJ -+endif -+ -+ifeq ($(CONFIG_RTL8822B), y) -+ifeq ($(CONFIG_SDIO_HCI), y) -+CONFIG_RTL8822BS ?= m -+USER_MODULE_NAME := 8822bs -+endif -+endif -+ -+endif -+ -+ifeq ($(CONFIG_PLATFORM_ZTE_ZX296716), y) -+EXTRA_CFLAGS += -Wno-error=date-time -+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ZTE_ZX296716 -+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -+# default setting for Android -+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE -+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -+EXTRA_CFLAGS += -DRTW_USE_CFG80211_STA_EVENT -+# default setting for Android 5.x and later -+#EXTRA_CFLAGS += -DCONFIG_RADIO_WORK -+ -+ifeq ($(CONFIG_SDIO_HCI), y) -+# mark this temporarily -+#EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS -+#_PLATFORM_FILES += platform/platform_zte_zx296716_sdio.o -+endif -+ -+ARCH ?= arm64 -+CROSS_COMPILE ?= -+KSRC ?= -+ -+ifeq ($(CONFIG_RTL8822B), y) -+ifeq ($(CONFIG_SDIO_HCI), y) -+CONFIG_RTL8822BS ?= m -+USER_MODULE_NAME := 8822bs -+endif -+endif -+ -+endif -+ -+########### CUSTOMER ################################ -+ifeq ($(CONFIG_CUSTOMER_HUAWEI_GENERAL), y) -+CONFIG_CUSTOMER_HUAWEI = y -+endif -+ -+ifeq ($(CONFIG_CUSTOMER_HUAWEI), y) -+EXTRA_CFLAGS += -DCONFIG_HUAWEI_PROC -+endif -+ -+ifeq ($(CONFIG_MULTIDRV), y) -+ -+ifeq ($(CONFIG_SDIO_HCI), y) -+MODULE_NAME := rtw_sdio -+endif -+ -+ifeq ($(CONFIG_USB_HCI), y) -+MODULE_NAME := rtw_usb -+endif -+ -+ifeq ($(CONFIG_PCI_HCI), y) -+MODULE_NAME := rtw_pci -+endif -+ -+endif -+ -+USER_MODULE_NAME ?= -+ifneq ($(USER_MODULE_NAME),) -+MODULE_NAME := $(USER_MODULE_NAME) -+endif -+ -+ifneq ($(KERNELRELEASE),) -+ -+########### this part for *.mk ############################ -+include $(src)/hal/phydm/phydm.mk -+ -+########### HAL_RTL8822B ################################# -+ifeq ($(CONFIG_RTL8822B), y) -+include $(src)/rtl8822b.mk -+endif -+ -+########### HAL_RTL8821C ################################# -+ifeq ($(CONFIG_RTL8821C), y) -+include $(src)/rtl8821c.mk -+endif -+ -+rtk_core := core/rtw_cmd.o \ -+ core/rtw_security.o \ -+ core/rtw_debug.o \ -+ core/rtw_io.o \ -+ core/rtw_ioctl_query.o \ -+ core/rtw_ioctl_set.o \ -+ core/rtw_ieee80211.o \ -+ core/rtw_mlme.o \ -+ core/rtw_mlme_ext.o \ -+ core/rtw_mi.o \ -+ core/rtw_wlan_util.o \ -+ core/rtw_vht.o \ -+ core/rtw_pwrctrl.o \ -+ core/rtw_rf.o \ -+ core/rtw_chplan.o \ -+ core/rtw_recv.o \ -+ core/rtw_sta_mgt.o \ -+ core/rtw_ap.o \ -+ core/mesh/rtw_mesh.o \ -+ core/mesh/rtw_mesh_pathtbl.o \ -+ core/mesh/rtw_mesh_hwmp.o \ -+ core/rtw_xmit.o \ -+ core/rtw_p2p.o \ -+ core/rtw_rson.o \ -+ core/rtw_tdls.o \ -+ core/rtw_br_ext.o \ -+ core/rtw_iol.o \ -+ core/rtw_sreset.o \ -+ core/rtw_btcoex_wifionly.o \ -+ core/rtw_btcoex.o \ -+ core/rtw_beamforming.o \ -+ core/rtw_odm.o \ -+ core/rtw_rm.o \ -+ core/rtw_rm_fsm.o \ -+ core/efuse/rtw_efuse.o -+ -+ifeq ($(CONFIG_SDIO_HCI), y) -+rtk_core += core/rtw_sdio.o -+endif -+ -+$(MODULE_NAME)-y += $(rtk_core) -+ -+$(MODULE_NAME)-$(CONFIG_INTEL_WIDI) += core/rtw_intel_widi.o -+ -+$(MODULE_NAME)-$(CONFIG_WAPI_SUPPORT) += core/rtw_wapi.o \ -+ core/rtw_wapi_sms4.o -+ -+$(MODULE_NAME)-y += $(_OS_INTFS_FILES) -+$(MODULE_NAME)-y += $(_HAL_INTFS_FILES) -+$(MODULE_NAME)-y += $(_PHYDM_FILES) -+$(MODULE_NAME)-y += $(_BTC_FILES) -+$(MODULE_NAME)-y += $(_PLATFORM_FILES) -+ -+$(MODULE_NAME)-$(CONFIG_MP_INCLUDED) += core/rtw_mp.o -+ -+obj-$(CONFIG_88XXAU) := $(MODULE_NAME).o -+ -+else -+ -+export CONFIG_88XXAU = m -+ -+all: modules -+ -+modules: -+ $(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KSRC) M=$(shell pwd) modules -+ @echo "---------------------------------------------------------------------------" -+ @echo "Visit https://github.com/aircrack-ng/rtl8812au for support/reporting issues" -+ @echo "or check for newer versions (branches) of these drivers. " -+ @echo "---------------------------------------------------------------------------" -+strip: -+ $(CROSS_COMPILE)strip $(MODULE_NAME).ko --strip-unneeded -+ -+install: -+ install -p -m 644 $(MODULE_NAME).ko $(MODDESTDIR) -+ /sbin/depmod -a ${KVER} -+ -+uninstall: -+ rm -f $(MODDESTDIR)/$(MODULE_NAME).ko -+ /sbin/depmod -a ${KVER} -+ -+backup_rtlwifi: -+ @echo "Making backup rtlwifi drivers" -+ifneq (,$(wildcard $(STAGINGMODDIR)/rtl*)) -+ @tar cPf $(wildcard $(STAGINGMODDIR))/backup_rtlwifi_driver.tar $(wildcard $(STAGINGMODDIR)/rtl*) -+ @rm -rf $(wildcard $(STAGINGMODDIR)/rtl*) -+endif -+ifneq (,$(wildcard $(MODDESTDIR)realtek)) -+ @tar cPf $(MODDESTDIR)backup_rtlwifi_driver.tar $(MODDESTDIR)realtek -+ @rm -fr $(MODDESTDIR)realtek -+endif -+ifneq (,$(wildcard $(MODDESTDIR)rtl*)) -+ @tar cPf $(MODDESTDIR)../backup_rtlwifi_driver.tar $(wildcard $(MODDESTDIR)rtl*) -+ @rm -fr $(wildcard $(MODDESTDIR)rtl*) -+endif -+ @/sbin/depmod -a ${KVER} -+ @echo "Please reboot your system" -+ -+restore_rtlwifi: -+ @echo "Restoring backups" -+ifneq (,$(wildcard $(STAGINGMODDIR)/backup_rtlwifi_driver.tar)) -+ @tar xPf $(STAGINGMODDIR)/backup_rtlwifi_driver.tar -+ @rm $(STAGINGMODDIR)/backup_rtlwifi_driver.tar -+endif -+ifneq (,$(wildcard $(MODDESTDIR)backup_rtlwifi_driver.tar)) -+ @tar xPf $(MODDESTDIR)backup_rtlwifi_driver.tar -+ @rm $(MODDESTDIR)backup_rtlwifi_driver.tar -+endif -+ifneq (,$(wildcard $(MODDESTDIR)../backup_rtlwifi_driver.tar)) -+ @tar xPf $(MODDESTDIR)../backup_rtlwifi_driver.tar -+ @rm $(MODDESTDIR)../backup_rtlwifi_driver.tar -+endif -+ @/sbin/depmod -a ${KVER} -+ @echo "Please reboot your system" -+ -+config_r: -+ @echo "make config" -+ /bin/bash script/Configure script/config.in -+ -+.PHONY: modules clean -+ -+clean: -+ #$(MAKE) -C $(KSRC) M=$(shell pwd) clean -+ cd hal ; rm -fr */*/*/*.mod.c */*/*/*.mod */*/*/*.o */*/*/.*.cmd */*/*/*.ko -+ cd hal ; rm -fr */*/*.mod.c */*/*.mod */*/*.o */*/.*.cmd */*/*.ko -+ cd hal ; rm -fr */*.mod.c */*.mod */*.o */.*.cmd */*.ko -+ cd hal ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko -+ cd core ; rm -fr */*.mod.c */*.mod */*.o */.*.cmd */*.ko -+ cd core ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko -+ cd os_dep/linux ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko *.o.d -+ cd os_dep ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko -+ cd platform ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko -+ rm -fr Module.symvers ; rm -fr Module.markers ; rm -fr modules.order -+ rm -fr *.mod.c *.mod *.o .*.cmd *.ko *~ -+ rm -fr .tmp_versions -+endif -diff --git linux-5.8/3rdparty/rtl8812au/README.md linux-5.8/3rdparty/rtl8812au/README.md -new file mode 100644 -index 000000000..1739873c3 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/README.md -@@ -0,0 +1,207 @@ -+## RTL8812AU/21AU and RTL8814AU drivers -+Only for use with Linux & Android -+ -+[![Monitor mode](https://img.shields.io/badge/monitor%20mode-working-brightgreen.svg)](#) -+[![Frame Injection](https://img.shields.io/badge/frame%20injection-working-brightgreen.svg)](#) -+[![GitHub version](https://raster.shields.io/badge/version-v5.6.4.2-lightgrey.svg)](#) -+[![GitHub issues](https://img.shields.io/github/issues/aircrack-ng/rtl8812au.svg)](https://github.com/aircrack-ng/rtl8812au/issues) -+[![GitHub forks](https://img.shields.io/github/forks/aircrack-ng/rtl8812au.svg)](https://github.com/aircrack-ng/rtl8812au/network) -+[![GitHub stars](https://img.shields.io/github/stars/aircrack-ng/rtl8812au.svg)](https://github.com/aircrack-ng/rtl8812au/stargazers) -+[![Build Status](https://travis-ci.org/aircrack-ng/rtl8812au.svg?branch=v5.6.4.2)](https://travis-ci.org/aircrack-ng/rtl8812au) -+[![GitHub license](https://img.shields.io/github/license/aircrack-ng/rtl8812au.svg)](https://github.com/aircrack-ng/rtl8812au/blob/master/LICENSE) -+
-+[![Kali](https://img.shields.io/badge/Kali-supported-blue.svg)](https://www.kali.org) -+[![Arch](https://img.shields.io/badge/Arch-supported-blue.svg)](https://www.archlinux.org) -+[![Armbian](https://img.shields.io/badge/Armbian-supported-blue.svg)](https://www.armbian.com) -+[![ArchLinux](https://img.shields.io/badge/ArchLinux-supported-blue.svg)](https://img.shields.io/badge/ArchLinux-supported-blue.svg) -+[![aircrack-ng](https://img.shields.io/badge/aircrack--ng-supported-blue.svg)](https://github.com/aircrack-ng/aircrack-ng) -+[![wifite2](https://img.shields.io/badge/wifite2-supported-blue.svg)](https://github.com/kimocoder/wifite2) -+ -+ -+### Important! -+``` -+* Use "ip" and "iw" instead of "ifconfig" and "iwconfig" -+ It's described further down, READ THE README! -+ -+* v5.3.4 is the stable branch, not this, but this does have -+ better range then branches below + more fixes from Realtek -+``` -+ -+### IPERF3 benchmark -+[Device] Alfa Networks AWUS036ACH
-+[Chipset] 88XXau (rtl8812au)
-+[Branch] v5.6.4.1
-+[Distance] 10m free sight -+``` -+[ ID] Interval Transfer Bitrate Retr Cwnd -+[ 5] 0.00-1.00 sec 11.6 MBytes 97.4 Mbits/sec 0 96.2 KBytes -+[ 5] 1.00-2.00 sec 11.2 MBytes 93.8 Mbits/sec 0 100 KBytes -+[ 5] 2.00-3.00 sec 11.2 MBytes 93.8 Mbits/sec 0 100 KBytes -+[ 5] 3.00-4.00 sec 11.2 MBytes 93.8 Mbits/sec 0 100 KBytes -+[ 5] 4.00-5.00 sec 11.2 MBytes 93.8 Mbits/sec 0 100 KBytes -+[ 5] 5.00-6.00 sec 11.4 MBytes 95.9 Mbits/sec 0 105 KBytes -+[ 5] 6.00-7.00 sec 11.2 MBytes 93.8 Mbits/sec 0 105 KBytes -+[ 5] 7.00-8.00 sec 11.3 MBytes 94.9 Mbits/sec 0 157 KBytes -+[ 5] 8.00-9.00 sec 11.2 MBytes 93.8 Mbits/sec 0 157 KBytes -+[ 5] 9.00-10.00 sec 11.2 MBytes 94.3 Mbits/sec 0 157 KBytes -+[ 5] 10.00-11.00 sec 11.2 MBytes 93.8 Mbits/sec 0 157 KBytes -+[ 5] 11.00-12.00 sec 11.2 MBytes 93.8 Mbits/sec 0 157 KBytes -+[ 5] 12.00-13.00 sec 11.2 MBytes 94.4 Mbits/sec 0 157 KBytes -+[ 5] 13.00-14.00 sec 11.2 MBytes 93.8 Mbits/sec 0 157 KBytes -+[ 5] 14.00-15.00 sec 11.2 MBytes 94.4 Mbits/sec 0 157 KBytes -+[ 5] 15.00-16.00 sec 10.9 MBytes 91.7 Mbits/sec 0 157 KBytes -+[ 5] 16.00-17.00 sec 11.2 MBytes 94.4 Mbits/sec 0 157 KBytes -+[ 5] 17.00-18.00 sec 11.2 MBytes 94.4 Mbits/sec 0 157 KBytes -+[ 5] 18.00-19.00 sec 11.2 MBytes 94.4 Mbits/sec 0 157 KBytes -+[ 5] 19.00-20.00 sec 11.2 MBytes 93.8 Mbits/sec 0 157 KBytes -+[ 5] 20.00-21.00 sec 11.2 MBytes 93.8 Mbits/sec 0 157 KBytes -+[ 5] 21.00-22.00 sec 11.2 MBytes 93.8 Mbits/sec 0 157 KBytes -+[ 5] 22.00-23.00 sec 11.2 MBytes 93.8 Mbits/sec 0 157 KBytes -+- - - - - - - - - - - - - - - - - - - - - - - - - -+[ ID] Interval Transfer Bitrate Retr -+[ 5] 0.00-23.15 sec 260 MBytes 94.2 Mbits/sec 0 sender -+[ 5] 0.00-23.15 sec 0.00 Bytes 0.00 bits/sec receiver -+``` -+ -+### DKMS -+This driver can be installed using [DKMS]. This is a system which will automatically recompile and install a kernel module when a new kernel gets installed or updated. To make use of DKMS, install the `dkms` package, which on Debian (based) systems is done like this: -+``` -+$ sudo apt-get install dkms -+``` -+ -+### Installation of Driver -+In order to install the driver open a terminal in the directory with the source code and execute the following command: -+``` -+$ sudo ./dkms-install.sh -+``` -+ -+### Removal of Driver -+In order to remove the driver from your system open a terminal in the directory with the source code and execute the following command: -+``` -+$ sudo ./dkms-remove.sh -+``` -+ -+### Make -+For building & installing the driver with 'make' use -+``` -+$ make && make install -+``` -+ -+### Notes -+Download -+``` -+$ git clone -b v5.6.4.2 https://github.com/aircrack-ng/rtl8812au.git -+cd rtl* -+``` -+Package / Build dependencies (Kali) -+``` -+$ sudo apt-get update -+$ sudo apt-get install build-essential libelf-dev linux-headers-`uname -r` -+``` -+#### For Raspberry (RPI) -+ -+``` -+$ sudo apt-get install raspberrypi-kernel-headers -+``` -+ -+Then run this step to change platform in Makefile, For RPI 1/2/3/ & 0/Zero: -+``` -+$ sed -i 's/CONFIG_PLATFORM_I386_PC = y/CONFIG_PLATFORM_I386_PC = n/g' Makefile -+$ sed -i 's/CONFIG_PLATFORM_ARM_RPI = n/CONFIG_PLATFORM_ARM_RPI = y/g' Makefile -+``` -+ -+But for RPI 3B+ & 4B you will need to run those below which builds the ARM64 arch driver: -+``` -+$ sed -i 's/CONFIG_PLATFORM_I386_PC = y/CONFIG_PLATFORM_I386_PC = n/g' Makefile -+$ sed -i 's/CONFIG_PLATFORM_ARM64_RPI = n/CONFIG_PLATFORM_ARM64_RPI = y/g' Makefile -+``` -+ -+In addition, if you receive an error message about `unrecognized command line option ‘-mgeneral-regs-only’` (i.e., Raspbian Buster), you will need to run the following commands: -+``` -+$ sed -i 's/^dkms build/ARCH=arm dkms build/' dkms-install.sh -+$ sed -i 's/^MAKE="/MAKE="ARCH=arm\ /' dkms.conf -+``` -+ -+For setting monitor mode -+ 1. Fix problematic interference in monitor mode. -+ ``` -+ $ airmon-ng check kill -+ ``` -+ You may also uncheck the box "Automatically connect to this network when it is avaiable" in nm-connection-editor. This only works if you have a saved wifi connection. -+ -+ 2. Set interface down -+ ``` -+ $ sudo ip link set wlan0 down -+ ``` -+ 3. Set monitor mode -+ ``` -+ $ sudo iw dev wlan0 set type monitor -+ ``` -+ 4. Set interface up -+ ``` -+ $ sudo ip link set wlan0 up -+ ``` -+For setting TX power -+``` -+$ sudo iw wlan0 set txpower fixed 3000 -+``` -+ -+### LED control -+ -+#### statically by module parameter in /etc/modprobe.d/8812au.conf or wherever, for example: -+ -+```sh -+options 88XXau rtw_led_ctrl=0 -+``` -+value can be 0 or 1 -+ -+#### or dynamically by writing to /proc/net/rtl8812au/$(your interface name)/led_ctrl, for example: -+ -+```sh -+$ echo "0" > /proc/net/rtl8812au/$(your interface name)/led_ctrl -+``` -+value can be 0 or 1 -+ -+#### check current value: -+ -+```sh -+$ cat /proc/net/rtl8812au/$(your interface name)/led_ctrl -+``` -+ -+### USB Mode Switch -+ -+0: doesn't switch, 1: switch from usb2.0 to usb 3.0 2: switch from usb3.0 to usb 2.0 -+```sh -+$ rmmod 88XXau -+$ modprobe 88XXau rtw_switch_usb_mode:int (0: no switch 1: switch from usb2 to usb3 2: switch from usb3 to usb2) -+``` -+ -+### NetworkManager -+ -+Newer versions of NetworkManager switches to random MAC address. Some users would prefer to use a fixed address. -+Simply add these lines below -+``` -+[device] -+wifi.scan-rand-mac-address=no -+``` -+at the end of file /etc/NetworkManager/NetworkManager.conf and restart NetworkManager with the command: -+``` -+$ sudo service NetworkManager restart -+``` -+ -+### Credits / Contributors -+ -+``` -+Alfa Networks - https://www.alfa.com.tw/ -+Realtek. - https://www.realtek.com -+aircrack-ng - https://www.aircrack-ng.org -+ -+astsam - https://github.com/astsam -+evilphish - https://github.com/evilphish -+fariouche - https://github.com/fariouche -+CGarces - https://github.com/CGarces -+ZerBea - https://github.com/ZerBea -+lwfinger - https://github.com/lwfinger -+Ulli-Kroll. - https://github.com/Ulli-Kroll -+ -+``` -diff --git linux-5.8/3rdparty/rtl8812au/ReleaseNotes.pdf linux-5.8/3rdparty/rtl8812au/ReleaseNotes.pdf -new file mode 100644 -index 000000000..6ead272e3 -Binary files /dev/null and linux-5.8/3rdparty/rtl8812au/ReleaseNotes.pdf differ -diff --git linux-5.8/3rdparty/rtl8812au/core/efuse/rtw_efuse.c linux-5.8/3rdparty/rtl8812au/core/efuse/rtw_efuse.c -new file mode 100644 -index 000000000..44d8ac468 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/efuse/rtw_efuse.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/efuse/rtw_efuse.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/efuse/rtw_efuse.c +--- linux-5.11.4/3rdparty/rtl8812au/core/efuse/rtw_efuse.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/efuse/rtw_efuse.c 2021-03-07 18:16:17.015954210 +0200 @@ -0,0 +1,3278 @@ +/****************************************************************************** + * @@ -6184,11 +3280,9 @@ index 000000000..44d8ac468 +#endif /* CONFIG_EFUSE_CONFIG_FILE */ + +#endif /* PLATFORM_LINUX */ -diff --git linux-5.8/3rdparty/rtl8812au/core/mesh/rtw_mesh.c linux-5.8/3rdparty/rtl8812au/core/mesh/rtw_mesh.c -new file mode 100644 -index 000000000..95d0f15ce ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/mesh/rtw_mesh.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/mesh/rtw_mesh.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/mesh/rtw_mesh.c +--- linux-5.11.4/3rdparty/rtl8812au/core/mesh/rtw_mesh.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/mesh/rtw_mesh.c 2021-03-07 18:16:17.016954257 +0200 @@ -0,0 +1,4080 @@ +/****************************************************************************** + * @@ -10270,11 +7364,9 @@ index 000000000..95d0f15ce +} +#endif /* CONFIG_RTW_MESH */ + -diff --git linux-5.8/3rdparty/rtl8812au/core/mesh/rtw_mesh.h linux-5.8/3rdparty/rtl8812au/core/mesh/rtw_mesh.h -new file mode 100644 -index 000000000..73694f84d ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/mesh/rtw_mesh.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/mesh/rtw_mesh.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/mesh/rtw_mesh.h +--- linux-5.11.4/3rdparty/rtl8812au/core/mesh/rtw_mesh.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/mesh/rtw_mesh.h 2021-03-07 18:16:17.016954257 +0200 @@ -0,0 +1,534 @@ +/****************************************************************************** + * @@ -10810,11 +7902,9 @@ index 000000000..73694f84d +#include "rtw_mesh_hwmp.h" +#endif /* __RTW_MESH_H_ */ + -diff --git linux-5.8/3rdparty/rtl8812au/core/mesh/rtw_mesh_hwmp.c linux-5.8/3rdparty/rtl8812au/core/mesh/rtw_mesh_hwmp.c -new file mode 100644 -index 000000000..f64aa3de9 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/mesh/rtw_mesh_hwmp.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/mesh/rtw_mesh_hwmp.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/mesh/rtw_mesh_hwmp.c +--- linux-5.11.4/3rdparty/rtl8812au/core/mesh/rtw_mesh_hwmp.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/mesh/rtw_mesh_hwmp.c 2021-03-07 18:16:17.016954257 +0200 @@ -0,0 +1,1665 @@ +/****************************************************************************** + * @@ -12481,11 +9571,9 @@ index 000000000..f64aa3de9 + +#endif /* CONFIG_RTW_MESH */ + -diff --git linux-5.8/3rdparty/rtl8812au/core/mesh/rtw_mesh_hwmp.h linux-5.8/3rdparty/rtl8812au/core/mesh/rtw_mesh_hwmp.h -new file mode 100644 -index 000000000..943341781 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/mesh/rtw_mesh_hwmp.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/mesh/rtw_mesh_hwmp.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/mesh/rtw_mesh_hwmp.h +--- linux-5.11.4/3rdparty/rtl8812au/core/mesh/rtw_mesh_hwmp.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/mesh/rtw_mesh_hwmp.h 2021-03-07 18:16:17.016954257 +0200 @@ -0,0 +1,60 @@ +/****************************************************************************** + * @@ -12547,11 +9635,9 @@ index 000000000..943341781 +#endif /* __RTW_MESH_HWMP_H_ */ + + -diff --git linux-5.8/3rdparty/rtl8812au/core/mesh/rtw_mesh_pathtbl.c linux-5.8/3rdparty/rtl8812au/core/mesh/rtw_mesh_pathtbl.c -new file mode 100644 -index 000000000..d8791603d ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/mesh/rtw_mesh_pathtbl.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/mesh/rtw_mesh_pathtbl.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/mesh/rtw_mesh_pathtbl.c +--- linux-5.11.4/3rdparty/rtl8812au/core/mesh/rtw_mesh_pathtbl.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/mesh/rtw_mesh_pathtbl.c 2021-03-07 18:16:17.016954257 +0200 @@ -0,0 +1,1237 @@ +/****************************************************************************** + * @@ -13790,11 +10876,9 @@ index 000000000..d8791603d +} +#endif /* CONFIG_RTW_MESH */ + -diff --git linux-5.8/3rdparty/rtl8812au/core/mesh/rtw_mesh_pathtbl.h linux-5.8/3rdparty/rtl8812au/core/mesh/rtw_mesh_pathtbl.h -new file mode 100644 -index 000000000..650b239f5 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/mesh/rtw_mesh_pathtbl.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/mesh/rtw_mesh_pathtbl.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/mesh/rtw_mesh_pathtbl.h +--- linux-5.11.4/3rdparty/rtl8812au/core/mesh/rtw_mesh_pathtbl.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/mesh/rtw_mesh_pathtbl.h 2021-03-07 18:16:17.016954257 +0200 @@ -0,0 +1,208 @@ +/****************************************************************************** + * @@ -14004,11 +11088,9 @@ index 000000000..650b239f5 + +#endif /* __RTW_MESH_PATHTBL_H_ */ + -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_ap.c linux-5.8/3rdparty/rtl8812au/core/rtw_ap.c -new file mode 100644 -index 000000000..bc78e9c19 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_ap.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_ap.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_ap.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_ap.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_ap.c 2021-03-07 18:16:17.017954304 +0200 @@ -0,0 +1,5476 @@ +/****************************************************************************** + * @@ -19486,11 +16568,9 @@ index 000000000..bc78e9c19 +} +#endif /* CONFIG_AP_MODE */ + -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_beamforming.c linux-5.8/3rdparty/rtl8812au/core/rtw_beamforming.c -new file mode 100644 -index 000000000..7e5fd7b94 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_beamforming.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_beamforming.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_beamforming.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_beamforming.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_beamforming.c 2021-03-07 18:16:17.017954304 +0200 @@ -0,0 +1,3155 @@ +/****************************************************************************** + * @@ -22647,11 +19727,9 @@ index 000000000..7e5fd7b94 +#endif /* !RTW_BEAMFORMING_VERSION_2 */ + +#endif /* CONFIG_BEAMFORMING */ -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_br_ext.c linux-5.8/3rdparty/rtl8812au/core/rtw_br_ext.c -new file mode 100644 -index 000000000..9a0effd8b ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_br_ext.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_br_ext.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_br_ext.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_br_ext.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_br_ext.c 2021-03-07 18:16:17.017954304 +0200 @@ -0,0 +1,1581 @@ +/****************************************************************************** + * @@ -24234,11 +21312,1831 @@ index 000000000..9a0effd8b +} + +#endif /* CONFIG_BR_EXT */ -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_bt_mp.c linux-5.8/3rdparty/rtl8812au/core/rtw_bt_mp.c -new file mode 100644 -index 000000000..9b4fc2432 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_bt_mp.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_btcoex.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_btcoex.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_btcoex.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_btcoex.c 2021-03-07 18:16:17.017954304 +0200 +@@ -0,0 +1,1767 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2013 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++#include ++#include ++#ifdef CONFIG_BT_COEXIST ++#include ++ ++void rtw_btcoex_Initialize(PADAPTER padapter) ++{ ++ hal_btcoex_Initialize(padapter); ++} ++ ++void rtw_btcoex_PowerOnSetting(PADAPTER padapter) ++{ ++ hal_btcoex_PowerOnSetting(padapter); ++} ++ ++void rtw_btcoex_AntInfoSetting(PADAPTER padapter) ++{ ++ hal_btcoex_AntInfoSetting(padapter); ++} ++ ++void rtw_btcoex_PowerOffSetting(PADAPTER padapter) ++{ ++ hal_btcoex_PowerOffSetting(padapter); ++} ++ ++void rtw_btcoex_PreLoadFirmware(PADAPTER padapter) ++{ ++ hal_btcoex_PreLoadFirmware(padapter); ++} ++ ++void rtw_btcoex_HAL_Initialize(PADAPTER padapter, u8 bWifiOnly) ++{ ++ hal_btcoex_InitHwConfig(padapter, bWifiOnly); ++} ++ ++void rtw_btcoex_IpsNotify(PADAPTER padapter, u8 type) ++{ ++ PHAL_DATA_TYPE pHalData; ++ ++ pHalData = GET_HAL_DATA(padapter); ++ if (_FALSE == pHalData->EEPROMBluetoothCoexist) ++ return; ++ ++ hal_btcoex_IpsNotify(padapter, type); ++} ++ ++void rtw_btcoex_LpsNotify(PADAPTER padapter, u8 type) ++{ ++ PHAL_DATA_TYPE pHalData; ++ ++ pHalData = GET_HAL_DATA(padapter); ++ if (_FALSE == pHalData->EEPROMBluetoothCoexist) ++ return; ++ ++ hal_btcoex_LpsNotify(padapter, type); ++} ++ ++void rtw_btcoex_ScanNotify(PADAPTER padapter, u8 type) ++{ ++ PHAL_DATA_TYPE pHalData; ++#ifdef CONFIG_BT_COEXIST_SOCKET_TRX ++ struct bt_coex_info *pcoex_info = &padapter->coex_info; ++ PBT_MGNT pBtMgnt = &pcoex_info->BtMgnt; ++#endif /* CONFIG_BT_COEXIST_SOCKET_TRX */ ++ ++ pHalData = GET_HAL_DATA(padapter); ++ if (_FALSE == pHalData->EEPROMBluetoothCoexist) ++ return; ++ ++ if (_FALSE == type) { ++ #ifdef CONFIG_CONCURRENT_MODE ++ if (rtw_mi_buddy_check_fwstate(padapter, WIFI_SITE_MONITOR)) ++ return; ++ #endif ++ ++ if (DEV_MGMT_TX_NUM(adapter_to_dvobj(padapter)) ++ || DEV_ROCH_NUM(adapter_to_dvobj(padapter))) ++ return; ++ } ++ ++#ifdef CONFIG_BT_COEXIST_SOCKET_TRX ++ if (pBtMgnt->ExtConfig.bEnableWifiScanNotify) ++ rtw_btcoex_SendScanNotify(padapter, type); ++#endif /* CONFIG_BT_COEXIST_SOCKET_TRX */ ++ ++ hal_btcoex_ScanNotify(padapter, type); ++} ++ ++void rtw_btcoex_ConnectNotify(PADAPTER padapter, u8 action) ++{ ++ PHAL_DATA_TYPE pHalData; ++ ++ pHalData = GET_HAL_DATA(padapter); ++ if (_FALSE == pHalData->EEPROMBluetoothCoexist) ++ return; ++ ++#ifdef DBG_CONFIG_ERROR_RESET ++ if (_TRUE == rtw_hal_sreset_inprogress(padapter)) { ++ RTW_INFO(FUNC_ADPT_FMT ": [BTCoex] under reset, skip notify!\n", ++ FUNC_ADPT_ARG(padapter)); ++ return; ++ } ++#endif /* DBG_CONFIG_ERROR_RESET */ ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if (_FALSE == action) { ++ if (rtw_mi_buddy_check_fwstate(padapter, WIFI_UNDER_LINKING)) ++ return; ++ } ++#endif ++ ++ hal_btcoex_ConnectNotify(padapter, action); ++} ++ ++void rtw_btcoex_MediaStatusNotify(PADAPTER padapter, u8 mediaStatus) ++{ ++ PHAL_DATA_TYPE pHalData; ++ ++ pHalData = GET_HAL_DATA(padapter); ++ if (_FALSE == pHalData->EEPROMBluetoothCoexist) ++ return; ++ ++#ifdef DBG_CONFIG_ERROR_RESET ++ if (_TRUE == rtw_hal_sreset_inprogress(padapter)) { ++ RTW_INFO(FUNC_ADPT_FMT ": [BTCoex] under reset, skip notify!\n", ++ FUNC_ADPT_ARG(padapter)); ++ return; ++ } ++#endif /* DBG_CONFIG_ERROR_RESET */ ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if (RT_MEDIA_DISCONNECT == mediaStatus) { ++ if (rtw_mi_buddy_check_fwstate(padapter, WIFI_ASOC_STATE)) ++ return; ++ } ++#endif /* CONFIG_CONCURRENT_MODE */ ++ ++ if ((RT_MEDIA_CONNECT == mediaStatus) ++ && (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == _TRUE)) ++ rtw_hal_set_hwreg(padapter, HW_VAR_DL_RSVD_PAGE, NULL); ++ ++ hal_btcoex_MediaStatusNotify(padapter, mediaStatus); ++} ++ ++void rtw_btcoex_SpecialPacketNotify(PADAPTER padapter, u8 pktType) ++{ ++ PHAL_DATA_TYPE pHalData; ++ ++ pHalData = GET_HAL_DATA(padapter); ++ if (_FALSE == pHalData->EEPROMBluetoothCoexist) ++ return; ++ ++ hal_btcoex_SpecialPacketNotify(padapter, pktType); ++} ++ ++void rtw_btcoex_IQKNotify(PADAPTER padapter, u8 state) ++{ ++ PHAL_DATA_TYPE pHalData; ++ ++ pHalData = GET_HAL_DATA(padapter); ++ if (_FALSE == pHalData->EEPROMBluetoothCoexist) ++ return; ++ ++ hal_btcoex_IQKNotify(padapter, state); ++} ++ ++void rtw_btcoex_BtInfoNotify(PADAPTER padapter, u8 length, u8 *tmpBuf) ++{ ++ PHAL_DATA_TYPE pHalData; ++ ++ pHalData = GET_HAL_DATA(padapter); ++ if (_FALSE == pHalData->EEPROMBluetoothCoexist) ++ return; ++ ++ hal_btcoex_BtInfoNotify(padapter, length, tmpBuf); ++} ++ ++void rtw_btcoex_BtMpRptNotify(PADAPTER padapter, u8 length, u8 *tmpBuf) ++{ ++ PHAL_DATA_TYPE pHalData; ++ ++ pHalData = GET_HAL_DATA(padapter); ++ if (_FALSE == pHalData->EEPROMBluetoothCoexist) ++ return; ++ ++ if (padapter->registrypriv.mp_mode == 1) ++ return; ++ ++ hal_btcoex_BtMpRptNotify(padapter, length, tmpBuf); ++} ++ ++void rtw_btcoex_SuspendNotify(PADAPTER padapter, u8 state) ++{ ++ PHAL_DATA_TYPE pHalData; ++ ++ pHalData = GET_HAL_DATA(padapter); ++ if (_FALSE == pHalData->EEPROMBluetoothCoexist) ++ return; ++ ++ hal_btcoex_SuspendNotify(padapter, state); ++} ++ ++void rtw_btcoex_HaltNotify(PADAPTER padapter) ++{ ++ PHAL_DATA_TYPE pHalData; ++ u8 do_halt = 1; ++ ++ pHalData = GET_HAL_DATA(padapter); ++ if (_FALSE == pHalData->EEPROMBluetoothCoexist) ++ do_halt = 0; ++ ++ if (_FALSE == padapter->bup) { ++ RTW_INFO(FUNC_ADPT_FMT ": bup=%d Skip!\n", ++ FUNC_ADPT_ARG(padapter), padapter->bup); ++ do_halt = 0; ++ } ++ ++ if (rtw_is_surprise_removed(padapter)) { ++ RTW_INFO(FUNC_ADPT_FMT ": bSurpriseRemoved=%s Skip!\n", ++ FUNC_ADPT_ARG(padapter), rtw_is_surprise_removed(padapter) ? "True" : "False"); ++ do_halt = 0; ++ } ++ ++ hal_btcoex_HaltNotify(padapter, do_halt); ++} ++ ++void rtw_btcoex_switchband_notify(u8 under_scan, u8 band_type) ++{ ++ hal_btcoex_switchband_notify(under_scan, band_type); ++} ++ ++void rtw_btcoex_WlFwDbgInfoNotify(PADAPTER padapter, u8* tmpBuf, u8 length) ++{ ++ hal_btcoex_WlFwDbgInfoNotify(padapter, tmpBuf, length); ++} ++ ++void rtw_btcoex_rx_rate_change_notify(PADAPTER padapter, u8 is_data_frame, u8 rate_id) ++{ ++ hal_btcoex_rx_rate_change_notify(padapter, is_data_frame, rate_id); ++} ++ ++void rtw_btcoex_SwitchBtTRxMask(PADAPTER padapter) ++{ ++ hal_btcoex_SwitchBtTRxMask(padapter); ++} ++ ++void rtw_btcoex_Switch(PADAPTER padapter, u8 enable) ++{ ++ hal_btcoex_SetBTCoexist(padapter, enable); ++} ++ ++u8 rtw_btcoex_IsBtDisabled(PADAPTER padapter) ++{ ++ return hal_btcoex_IsBtDisabled(padapter); ++} ++ ++void rtw_btcoex_Handler(PADAPTER padapter) ++{ ++ PHAL_DATA_TYPE pHalData; ++ ++ pHalData = GET_HAL_DATA(padapter); ++ ++ if (_FALSE == pHalData->EEPROMBluetoothCoexist) ++ return; ++ ++ hal_btcoex_Hanlder(padapter); ++} ++ ++s32 rtw_btcoex_IsBTCoexRejectAMPDU(PADAPTER padapter) ++{ ++ s32 coexctrl; ++ ++ coexctrl = hal_btcoex_IsBTCoexRejectAMPDU(padapter); ++ ++ return coexctrl; ++} ++ ++s32 rtw_btcoex_IsBTCoexCtrlAMPDUSize(PADAPTER padapter) ++{ ++ s32 coexctrl; ++ ++ coexctrl = hal_btcoex_IsBTCoexCtrlAMPDUSize(padapter); ++ ++ return coexctrl; ++} ++ ++u32 rtw_btcoex_GetAMPDUSize(PADAPTER padapter) ++{ ++ u32 size; ++ ++ size = hal_btcoex_GetAMPDUSize(padapter); ++ ++ return size; ++} ++ ++void rtw_btcoex_SetManualControl(PADAPTER padapter, u8 manual) ++{ ++ if (_TRUE == manual) ++ hal_btcoex_SetManualControl(padapter, _TRUE); ++ else ++ hal_btcoex_SetManualControl(padapter, _FALSE); ++} ++ ++u8 rtw_btcoex_1Ant(PADAPTER padapter) ++{ ++ return hal_btcoex_1Ant(padapter); ++} ++ ++u8 rtw_btcoex_IsBtControlLps(PADAPTER padapter) ++{ ++ return hal_btcoex_IsBtControlLps(padapter); ++} ++ ++u8 rtw_btcoex_IsLpsOn(PADAPTER padapter) ++{ ++ return hal_btcoex_IsLpsOn(padapter); ++} ++ ++u8 rtw_btcoex_RpwmVal(PADAPTER padapter) ++{ ++ return hal_btcoex_RpwmVal(padapter); ++} ++ ++u8 rtw_btcoex_LpsVal(PADAPTER padapter) ++{ ++ return hal_btcoex_LpsVal(padapter); ++} ++ ++u32 rtw_btcoex_GetRaMask(PADAPTER padapter) ++{ ++ return hal_btcoex_GetRaMask(padapter); ++} ++ ++void rtw_btcoex_RecordPwrMode(PADAPTER padapter, u8 *pCmdBuf, u8 cmdLen) ++{ ++ hal_btcoex_RecordPwrMode(padapter, pCmdBuf, cmdLen); ++} ++ ++void rtw_btcoex_DisplayBtCoexInfo(PADAPTER padapter, u8 *pbuf, u32 bufsize) ++{ ++ hal_btcoex_DisplayBtCoexInfo(padapter, pbuf, bufsize); ++} ++ ++void rtw_btcoex_SetDBG(PADAPTER padapter, u32 *pDbgModule) ++{ ++ hal_btcoex_SetDBG(padapter, pDbgModule); ++} ++ ++u32 rtw_btcoex_GetDBG(PADAPTER padapter, u8 *pStrBuf, u32 bufSize) ++{ ++ return hal_btcoex_GetDBG(padapter, pStrBuf, bufSize); ++} ++ ++u8 rtw_btcoex_IncreaseScanDeviceNum(PADAPTER padapter) ++{ ++ return hal_btcoex_IncreaseScanDeviceNum(padapter); ++} ++ ++u8 rtw_btcoex_IsBtLinkExist(PADAPTER padapter) ++{ ++ return hal_btcoex_IsBtLinkExist(padapter); ++} ++ ++void rtw_btcoex_SetBtPatchVersion(PADAPTER padapter, u16 btHciVer, u16 btPatchVer) ++{ ++ hal_btcoex_SetBtPatchVersion(padapter, btHciVer, btPatchVer); ++} ++ ++void rtw_btcoex_SetHciVersion(PADAPTER padapter, u16 hciVersion) ++{ ++ hal_btcoex_SetHciVersion(padapter, hciVersion); ++} ++ ++void rtw_btcoex_StackUpdateProfileInfo(void) ++{ ++ hal_btcoex_StackUpdateProfileInfo(); ++} ++ ++void rtw_btcoex_pta_off_on_notify(PADAPTER padapter, u8 bBTON) ++{ ++ hal_btcoex_pta_off_on_notify(padapter, bBTON); ++} ++ ++#ifdef CONFIG_RF4CE_COEXIST ++void rtw_btcoex_SetRf4ceLinkState(PADAPTER padapter, u8 state) ++{ ++ hal_btcoex_set_rf4ce_link_state(state); ++} ++ ++u8 rtw_btcoex_GetRf4ceLinkState(PADAPTER padapter) ++{ ++ return hal_btcoex_get_rf4ce_link_state(); ++} ++#endif ++ ++/* ================================================== ++ * Below Functions are called by BT-Coex ++ * ================================================== */ ++void rtw_btcoex_rx_ampdu_apply(PADAPTER padapter) ++{ ++ rtw_rx_ampdu_apply(padapter); ++} ++ ++void rtw_btcoex_LPS_Enter(PADAPTER padapter) ++{ ++ struct pwrctrl_priv *pwrpriv; ++ u8 lpsVal; ++ ++ ++ pwrpriv = adapter_to_pwrctl(padapter); ++ ++ pwrpriv->bpower_saving = _TRUE; ++ lpsVal = rtw_btcoex_LpsVal(padapter); ++ rtw_set_ps_mode(padapter, PS_MODE_MIN, 0, lpsVal, "BTCOEX"); ++} ++ ++u8 rtw_btcoex_LPS_Leave(PADAPTER padapter) ++{ ++ struct pwrctrl_priv *pwrpriv; ++ ++ ++ pwrpriv = adapter_to_pwrctl(padapter); ++ ++ if (pwrpriv->pwr_mode != PS_MODE_ACTIVE) { ++ rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0, "BTCOEX"); ++ pwrpriv->bpower_saving = _FALSE; ++ } ++ ++ return _TRUE; ++} ++ ++u16 rtw_btcoex_btreg_read(PADAPTER padapter, u8 type, u16 addr, u32 *data) ++{ ++ return hal_btcoex_btreg_read(padapter, type, addr, data); ++} ++ ++u16 rtw_btcoex_btreg_write(PADAPTER padapter, u8 type, u16 addr, u16 val) ++{ ++ return hal_btcoex_btreg_write(padapter, type, addr, val); ++} ++ ++u8 rtw_btcoex_get_bt_coexist(PADAPTER padapter) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ ++ return pHalData->EEPROMBluetoothCoexist; ++} ++ ++u8 rtw_btcoex_get_chip_type(PADAPTER padapter) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ ++ return pHalData->EEPROMBluetoothType; ++} ++ ++u8 rtw_btcoex_get_pg_ant_num(PADAPTER padapter) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ ++ return pHalData->EEPROMBluetoothAntNum == Ant_x2 ? 2 : 1; ++} ++ ++u8 rtw_btcoex_get_pg_single_ant_path(PADAPTER padapter) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ ++ return pHalData->ant_path; ++} ++ ++u8 rtw_btcoex_get_pg_rfe_type(PADAPTER padapter) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ ++ return pHalData->rfe_type; ++} ++ ++u8 rtw_btcoex_is_tfbga_package_type(PADAPTER padapter) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ ++#ifdef CONFIG_RTL8723B ++ if ((pHalData->PackageType == PACKAGE_TFBGA79) || (pHalData->PackageType == PACKAGE_TFBGA80) ++ || (pHalData->PackageType == PACKAGE_TFBGA90)) ++ return _TRUE; ++#endif ++ ++ return _FALSE; ++} ++ ++u8 rtw_btcoex_get_ant_div_cfg(PADAPTER padapter) ++{ ++ PHAL_DATA_TYPE pHalData; ++ ++ pHalData = GET_HAL_DATA(padapter); ++ ++ return (pHalData->AntDivCfg == 0) ? _FALSE : _TRUE; ++} ++ ++/* ================================================== ++ * Below Functions are BT-Coex socket related function ++ * ================================================== */ ++ ++#ifdef CONFIG_BT_COEXIST_SOCKET_TRX ++_adapter *pbtcoexadapter; /* = NULL; */ /* do not initialise globals to 0 or NULL */ ++u8 rtw_btcoex_btinfo_cmd(_adapter *adapter, u8 *buf, u16 len) ++{ ++ struct cmd_obj *ph2c; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ u8 *btinfo; ++ struct cmd_priv *pcmdpriv = &adapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if (ph2c == NULL) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); ++ if (pdrvextra_cmd_parm == NULL) { ++ rtw_mfree((u8 *)ph2c, sizeof(struct cmd_obj)); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ btinfo = rtw_zmalloc(len); ++ if (btinfo == NULL) { ++ rtw_mfree((u8 *)ph2c, sizeof(struct cmd_obj)); ++ rtw_mfree((u8 *)pdrvextra_cmd_parm, sizeof(struct drvextra_cmd_parm)); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = BTINFO_WK_CID; ++ pdrvextra_cmd_parm->type = 0; ++ pdrvextra_cmd_parm->size = len; ++ pdrvextra_cmd_parm->pbuf = btinfo; ++ ++ _rtw_memcpy(btinfo, buf, len); ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ return res; ++} ++ ++u8 rtw_btcoex_send_event_to_BT(_adapter *padapter, u8 status, u8 event_code, u8 opcode_low, u8 opcode_high, u8 *dbg_msg) ++{ ++ u8 localBuf[6] = ""; ++ u8 *pRetPar; ++ u8 len = 0, tx_event_length = 0; ++ rtw_HCI_event *pEvent; ++ ++ pEvent = (rtw_HCI_event *)(&localBuf[0]); ++ ++ pEvent->EventCode = event_code; ++ pEvent->Data[0] = 0x1; /* packet # */ ++ pEvent->Data[1] = opcode_low; ++ pEvent->Data[2] = opcode_high; ++ len = len + 3; ++ ++ /* Return parameters starts from here */ ++ pRetPar = &pEvent->Data[len]; ++ pRetPar[0] = status; /* status */ ++ ++ len++; ++ pEvent->Length = len; ++ ++ /* total tx event length + EventCode length + sizeof(length) */ ++ tx_event_length = pEvent->Length + 2; ++#if 0 ++ rtw_btcoex_dump_tx_msg((u8 *)pEvent, tx_event_length, dbg_msg); ++#endif ++ status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); ++ ++ return status; ++} ++ ++/* ++Ref: ++Realtek Wi-Fi Driver ++Host Controller Interface for ++Bluetooth 3.0 + HS V1.4 2013/02/07 ++ ++Window team code & BT team code ++ */ ++ ++ ++u8 rtw_btcoex_parse_BT_info_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) ++{ ++#define BT_INFO_LENGTH 8 ++ ++ u8 curPollEnable = pcmd[0]; ++ u8 curPollTime = pcmd[1]; ++ u8 btInfoReason = pcmd[2]; ++ u8 btInfoLen = pcmd[3]; ++ u8 btinfo[BT_INFO_LENGTH]; ++ ++ u8 localBuf[6] = ""; ++ u8 *pRetPar; ++ u8 len = 0, tx_event_length = 0; ++ RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; ++ rtw_HCI_event *pEvent; ++ ++ /* RTW_INFO("%s\n",__func__); ++ RTW_INFO("current Poll Enable: %d, currrent Poll Time: %d\n",curPollEnable,curPollTime); ++ RTW_INFO("BT Info reason: %d, BT Info length: %d\n",btInfoReason,btInfoLen); ++ RTW_INFO("%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n" ++ ,pcmd[4],pcmd[5],pcmd[6],pcmd[7],pcmd[8],pcmd[9],pcmd[10],pcmd[11]);*/ ++ ++ _rtw_memset(btinfo, 0, BT_INFO_LENGTH); ++ ++#if 1 ++ if (BT_INFO_LENGTH != btInfoLen) { ++ status = HCI_STATUS_INVALID_HCI_CMD_PARA_VALUE; ++ RTW_INFO("Error BT Info Length: %d\n", btInfoLen); ++ /* return _FAIL; */ ++ } else ++#endif ++ { ++ if (0x1 == btInfoReason || 0x2 == btInfoReason) { ++ _rtw_memcpy(btinfo, &pcmd[4], btInfoLen); ++ btinfo[0] = btInfoReason; ++ rtw_btcoex_btinfo_cmd(padapter, btinfo, btInfoLen); ++ } else ++ RTW_INFO("Other BT info reason\n"); ++ } ++ ++ /* send complete event to BT */ ++ { ++ ++ pEvent = (rtw_HCI_event *)(&localBuf[0]); ++ ++ pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; ++ pEvent->Data[0] = 0x1; /* packet # */ ++ pEvent->Data[1] = HCIOPCODELOW(HCI_BT_INFO_NOTIFY, OGF_EXTENSION); ++ pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_INFO_NOTIFY, OGF_EXTENSION); ++ len = len + 3; ++ ++ /* Return parameters starts from here */ ++ pRetPar = &pEvent->Data[len]; ++ pRetPar[0] = status; /* status */ ++ ++ len++; ++ pEvent->Length = len; ++ ++ /* total tx event length + EventCode length + sizeof(length) */ ++ tx_event_length = pEvent->Length + 2; ++#if 0 ++ rtw_btcoex_dump_tx_msg((u8 *)pEvent, tx_event_length, "BT_info_event"); ++#endif ++ status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); ++ ++ return status; ++ /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ ++ } ++} ++ ++u8 rtw_btcoex_parse_BT_patch_ver_info_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) ++{ ++ RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; ++ u16 btPatchVer = 0x0, btHciVer = 0x0; ++ /* u16 *pU2tmp; */ ++ ++ u8 localBuf[6] = ""; ++ u8 *pRetPar; ++ u8 len = 0, tx_event_length = 0; ++ rtw_HCI_event *pEvent; ++ ++ btHciVer = pcmd[0] | pcmd[1] << 8; ++ btPatchVer = pcmd[2] | pcmd[3] << 8; ++ ++ ++ RTW_INFO("%s, cmd:%02x %02x %02x %02x\n", __func__, pcmd[0] , pcmd[1] , pcmd[2] , pcmd[3]); ++ RTW_INFO("%s, HCI Ver:%d, Patch Ver:%d\n", __func__, btHciVer, btPatchVer); ++ ++ rtw_btcoex_SetBtPatchVersion(padapter, btHciVer, btPatchVer); ++ ++ ++ /* send complete event to BT */ ++ { ++ pEvent = (rtw_HCI_event *)(&localBuf[0]); ++ ++ ++ pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; ++ pEvent->Data[0] = 0x1; /* packet # */ ++ pEvent->Data[1] = HCIOPCODELOW(HCI_BT_PATCH_VERSION_NOTIFY, OGF_EXTENSION); ++ pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_PATCH_VERSION_NOTIFY, OGF_EXTENSION); ++ len = len + 3; ++ ++ /* Return parameters starts from here */ ++ pRetPar = &pEvent->Data[len]; ++ pRetPar[0] = status; /* status */ ++ ++ len++; ++ pEvent->Length = len; ++ ++ /* total tx event length + EventCode length + sizeof(length) */ ++ tx_event_length = pEvent->Length + 2; ++#if 0 ++ rtw_btcoex_dump_tx_msg((u8 *)pEvent, tx_event_length, "BT_patch_event"); ++#endif ++ status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); ++ return status; ++ /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ ++ } ++} ++ ++u8 rtw_btcoex_parse_HCI_Ver_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) ++{ ++ RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; ++ u16 hciver = pcmd[0] | pcmd[1] << 8; ++ ++ u8 localBuf[6] = ""; ++ u8 *pRetPar; ++ u8 len = 0, tx_event_length = 0; ++ rtw_HCI_event *pEvent; ++ ++ struct bt_coex_info *pcoex_info = &padapter->coex_info; ++ PBT_MGNT pBtMgnt = &pcoex_info->BtMgnt; ++ pBtMgnt->ExtConfig.HCIExtensionVer = hciver; ++ RTW_INFO("%s, HCI Version: %d\n", __func__, pBtMgnt->ExtConfig.HCIExtensionVer); ++ if (pBtMgnt->ExtConfig.HCIExtensionVer < 4) { ++ status = HCI_STATUS_INVALID_HCI_CMD_PARA_VALUE; ++ RTW_INFO("%s, Version = %d, HCI Version < 4\n", __func__, pBtMgnt->ExtConfig.HCIExtensionVer); ++ } else ++ rtw_btcoex_SetHciVersion(padapter, hciver); ++ /* send complete event to BT */ ++ { ++ pEvent = (rtw_HCI_event *)(&localBuf[0]); ++ ++ ++ pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; ++ pEvent->Data[0] = 0x1; /* packet # */ ++ pEvent->Data[1] = HCIOPCODELOW(HCI_EXTENSION_VERSION_NOTIFY, OGF_EXTENSION); ++ pEvent->Data[2] = HCIOPCODEHIGHT(HCI_EXTENSION_VERSION_NOTIFY, OGF_EXTENSION); ++ len = len + 3; ++ ++ /* Return parameters starts from here */ ++ pRetPar = &pEvent->Data[len]; ++ pRetPar[0] = status; /* status */ ++ ++ len++; ++ pEvent->Length = len; ++ ++ /* total tx event length + EventCode length + sizeof(length) */ ++ tx_event_length = pEvent->Length + 2; ++ ++ status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); ++ return status; ++ /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ ++ } ++ ++} ++ ++u8 rtw_btcoex_parse_WIFI_scan_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) ++{ ++ RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; ++ ++ u8 localBuf[6] = ""; ++ u8 *pRetPar; ++ u8 len = 0, tx_event_length = 0; ++ rtw_HCI_event *pEvent; ++ ++ struct bt_coex_info *pcoex_info = &padapter->coex_info; ++ PBT_MGNT pBtMgnt = &pcoex_info->BtMgnt; ++ pBtMgnt->ExtConfig.bEnableWifiScanNotify = pcmd[0]; ++ RTW_INFO("%s, bEnableWifiScanNotify: %d\n", __func__, pBtMgnt->ExtConfig.bEnableWifiScanNotify); ++ ++ /* send complete event to BT */ ++ { ++ pEvent = (rtw_HCI_event *)(&localBuf[0]); ++ ++ ++ pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; ++ pEvent->Data[0] = 0x1; /* packet # */ ++ pEvent->Data[1] = HCIOPCODELOW(HCI_ENABLE_WIFI_SCAN_NOTIFY, OGF_EXTENSION); ++ pEvent->Data[2] = HCIOPCODEHIGHT(HCI_ENABLE_WIFI_SCAN_NOTIFY, OGF_EXTENSION); ++ len = len + 3; ++ ++ /* Return parameters starts from here */ ++ pRetPar = &pEvent->Data[len]; ++ pRetPar[0] = status; /* status */ ++ ++ len++; ++ pEvent->Length = len; ++ ++ /* total tx event length + EventCode length + sizeof(length) */ ++ tx_event_length = pEvent->Length + 2; ++ ++ status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); ++ return status; ++ /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ ++ } ++} ++ ++u8 rtw_btcoex_parse_HCI_link_status_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) ++{ ++ RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; ++ struct bt_coex_info *pcoex_info = &padapter->coex_info; ++ PBT_MGNT pBtMgnt = &pcoex_info->BtMgnt; ++ /* PBT_DBG pBtDbg=&padapter->MgntInfo.BtInfo.BtDbg; */ ++ u8 i, numOfHandle = 0, numOfAcl = 0; ++ u16 conHandle; ++ u8 btProfile, btCoreSpec, linkRole; ++ u8 *pTriple; ++ ++ u8 localBuf[6] = ""; ++ u8 *pRetPar; ++ u8 len = 0, tx_event_length = 0; ++ rtw_HCI_event *pEvent; ++ ++ /* pBtDbg->dbgHciInfo.hciCmdCntLinkStatusNotify++; */ ++ /* RT_DISP_DATA(FIOCTL, IOCTL_BT_HCICMD_EXT, "LinkStatusNotify, Hex Data :\n", */ ++ /* &pHciCmd->Data[0], pHciCmd->Length); */ ++ ++ RTW_INFO("BTLinkStatusNotify\n"); ++ ++ /* Current only RTL8723 support this command. */ ++ /* pBtMgnt->bSupportProfile = TRUE; */ ++ pBtMgnt->bSupportProfile = _FALSE; ++ ++ pBtMgnt->ExtConfig.NumberOfACL = 0; ++ pBtMgnt->ExtConfig.NumberOfSCO = 0; ++ ++ numOfHandle = pcmd[0]; ++ /* RT_DISP(FIOCTL, IOCTL_BT_HCICMD_EXT, ("numOfHandle = 0x%x\n", numOfHandle)); */ ++ /* RT_DISP(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCIExtensionVer = %d\n", pBtMgnt->ExtConfig.HCIExtensionVer)); */ ++ RTW_INFO("numOfHandle = 0x%x\n", numOfHandle); ++ RTW_INFO("HCIExtensionVer = %d\n", pBtMgnt->ExtConfig.HCIExtensionVer); ++ ++ pTriple = &pcmd[1]; ++ for (i = 0; i < numOfHandle; i++) { ++ if (pBtMgnt->ExtConfig.HCIExtensionVer < 1) { ++ conHandle = *((u8 *)&pTriple[0]); ++ btProfile = pTriple[2]; ++ btCoreSpec = pTriple[3]; ++ if (BT_PROFILE_SCO == btProfile) ++ pBtMgnt->ExtConfig.NumberOfSCO++; ++ else { ++ pBtMgnt->ExtConfig.NumberOfACL++; ++ pBtMgnt->ExtConfig.aclLink[i].ConnectHandle = conHandle; ++ pBtMgnt->ExtConfig.aclLink[i].BTProfile = btProfile; ++ pBtMgnt->ExtConfig.aclLink[i].BTCoreSpec = btCoreSpec; ++ } ++ /* RT_DISP(FIOCTL, IOCTL_BT_HCICMD_EXT, */ ++ /* ("Connection_Handle=0x%x, BTProfile=%d, BTSpec=%d\n", */ ++ /* conHandle, btProfile, btCoreSpec)); */ ++ RTW_INFO("Connection_Handle=0x%x, BTProfile=%d, BTSpec=%d\n", conHandle, btProfile, btCoreSpec); ++ pTriple += 4; ++ } else if (pBtMgnt->ExtConfig.HCIExtensionVer >= 1) { ++ conHandle = *((pu2Byte)&pTriple[0]); ++ btProfile = pTriple[2]; ++ btCoreSpec = pTriple[3]; ++ linkRole = pTriple[4]; ++ if (BT_PROFILE_SCO == btProfile) ++ pBtMgnt->ExtConfig.NumberOfSCO++; ++ else { ++ pBtMgnt->ExtConfig.NumberOfACL++; ++ pBtMgnt->ExtConfig.aclLink[i].ConnectHandle = conHandle; ++ pBtMgnt->ExtConfig.aclLink[i].BTProfile = btProfile; ++ pBtMgnt->ExtConfig.aclLink[i].BTCoreSpec = btCoreSpec; ++ pBtMgnt->ExtConfig.aclLink[i].linkRole = linkRole; ++ } ++ /* RT_DISP(FIOCTL, IOCTL_BT_HCICMD_EXT, */ ++ RTW_INFO("Connection_Handle=0x%x, BTProfile=%d, BTSpec=%d, LinkRole=%d\n", ++ conHandle, btProfile, btCoreSpec, linkRole); ++ pTriple += 5; ++ } ++ } ++ rtw_btcoex_StackUpdateProfileInfo(); ++ ++ /* send complete event to BT */ ++ { ++ pEvent = (rtw_HCI_event *)(&localBuf[0]); ++ ++ ++ pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; ++ pEvent->Data[0] = 0x1; /* packet # */ ++ pEvent->Data[1] = HCIOPCODELOW(HCI_LINK_STATUS_NOTIFY, OGF_EXTENSION); ++ pEvent->Data[2] = HCIOPCODEHIGHT(HCI_LINK_STATUS_NOTIFY, OGF_EXTENSION); ++ len = len + 3; ++ ++ /* Return parameters starts from here */ ++ pRetPar = &pEvent->Data[len]; ++ pRetPar[0] = status; /* status */ ++ ++ len++; ++ pEvent->Length = len; ++ ++ /* total tx event length + EventCode length + sizeof(length) */ ++ tx_event_length = pEvent->Length + 2; ++ ++ status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); ++ return status; ++ /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ ++ } ++ ++ ++} ++ ++u8 rtw_btcoex_parse_HCI_BT_coex_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) ++{ ++ u8 localBuf[6] = ""; ++ u8 *pRetPar; ++ u8 len = 0, tx_event_length = 0; ++ rtw_HCI_event *pEvent; ++ RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; ++ ++ { ++ pEvent = (rtw_HCI_event *)(&localBuf[0]); ++ ++ ++ pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; ++ pEvent->Data[0] = 0x1; /* packet # */ ++ pEvent->Data[1] = HCIOPCODELOW(HCI_BT_COEX_NOTIFY, OGF_EXTENSION); ++ pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_COEX_NOTIFY, OGF_EXTENSION); ++ len = len + 3; ++ ++ /* Return parameters starts from here */ ++ pRetPar = &pEvent->Data[len]; ++ pRetPar[0] = status; /* status */ ++ ++ len++; ++ pEvent->Length = len; ++ ++ /* total tx event length + EventCode length + sizeof(length) */ ++ tx_event_length = pEvent->Length + 2; ++ ++ status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); ++ return status; ++ /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ ++ } ++} ++ ++u8 rtw_btcoex_parse_HCI_BT_operation_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) ++{ ++ u8 localBuf[6] = ""; ++ u8 *pRetPar; ++ u8 len = 0, tx_event_length = 0; ++ rtw_HCI_event *pEvent; ++ RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; ++ ++ RTW_INFO("%s, OP code: %d\n", __func__, pcmd[0]); ++ ++ switch (pcmd[0]) { ++ case HCI_BT_OP_NONE: ++ RTW_INFO("[bt operation] : Operation None!!\n"); ++ break; ++ case HCI_BT_OP_INQUIRY_START: ++ RTW_INFO("[bt operation] : Inquiry start!!\n"); ++ break; ++ case HCI_BT_OP_INQUIRY_FINISH: ++ RTW_INFO("[bt operation] : Inquiry finished!!\n"); ++ break; ++ case HCI_BT_OP_PAGING_START: ++ RTW_INFO("[bt operation] : Paging is started!!\n"); ++ break; ++ case HCI_BT_OP_PAGING_SUCCESS: ++ RTW_INFO("[bt operation] : Paging complete successfully!!\n"); ++ break; ++ case HCI_BT_OP_PAGING_UNSUCCESS: ++ RTW_INFO("[bt operation] : Paging complete unsuccessfully!!\n"); ++ break; ++ case HCI_BT_OP_PAIRING_START: ++ RTW_INFO("[bt operation] : Pairing start!!\n"); ++ break; ++ case HCI_BT_OP_PAIRING_FINISH: ++ RTW_INFO("[bt operation] : Pairing finished!!\n"); ++ break; ++ case HCI_BT_OP_BT_DEV_ENABLE: ++ RTW_INFO("[bt operation] : BT Device is enabled!!\n"); ++ break; ++ case HCI_BT_OP_BT_DEV_DISABLE: ++ RTW_INFO("[bt operation] : BT Device is disabled!!\n"); ++ break; ++ default: ++ RTW_INFO("[bt operation] : Unknown, error!!\n"); ++ break; ++ } ++ ++ /* send complete event to BT */ ++ { ++ pEvent = (rtw_HCI_event *)(&localBuf[0]); ++ ++ ++ pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; ++ pEvent->Data[0] = 0x1; /* packet # */ ++ pEvent->Data[1] = HCIOPCODELOW(HCI_BT_OPERATION_NOTIFY, OGF_EXTENSION); ++ pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_OPERATION_NOTIFY, OGF_EXTENSION); ++ len = len + 3; ++ ++ /* Return parameters starts from here */ ++ pRetPar = &pEvent->Data[len]; ++ pRetPar[0] = status; /* status */ ++ ++ len++; ++ pEvent->Length = len; ++ ++ /* total tx event length + EventCode length + sizeof(length) */ ++ tx_event_length = pEvent->Length + 2; ++ ++ status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); ++ return status; ++ /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ ++ } ++} ++ ++u8 rtw_btcoex_parse_BT_AFH_MAP_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) ++{ ++ u8 localBuf[6] = ""; ++ u8 *pRetPar; ++ u8 len = 0, tx_event_length = 0; ++ rtw_HCI_event *pEvent; ++ RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; ++ ++ { ++ pEvent = (rtw_HCI_event *)(&localBuf[0]); ++ ++ ++ pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; ++ pEvent->Data[0] = 0x1; /* packet # */ ++ pEvent->Data[1] = HCIOPCODELOW(HCI_BT_AFH_MAP_NOTIFY, OGF_EXTENSION); ++ pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_AFH_MAP_NOTIFY, OGF_EXTENSION); ++ len = len + 3; ++ ++ /* Return parameters starts from here */ ++ pRetPar = &pEvent->Data[len]; ++ pRetPar[0] = status; /* status */ ++ ++ len++; ++ pEvent->Length = len; ++ ++ /* total tx event length + EventCode length + sizeof(length) */ ++ tx_event_length = pEvent->Length + 2; ++ ++ status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); ++ return status; ++ /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ ++ } ++} ++ ++u8 rtw_btcoex_parse_BT_register_val_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) ++{ ++ ++ u8 localBuf[6] = ""; ++ u8 *pRetPar; ++ u8 len = 0, tx_event_length = 0; ++ rtw_HCI_event *pEvent; ++ RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; ++ ++ { ++ pEvent = (rtw_HCI_event *)(&localBuf[0]); ++ ++ ++ pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; ++ pEvent->Data[0] = 0x1; /* packet # */ ++ pEvent->Data[1] = HCIOPCODELOW(HCI_BT_REGISTER_VALUE_NOTIFY, OGF_EXTENSION); ++ pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_REGISTER_VALUE_NOTIFY, OGF_EXTENSION); ++ len = len + 3; ++ ++ /* Return parameters starts from here */ ++ pRetPar = &pEvent->Data[len]; ++ pRetPar[0] = status; /* status */ ++ ++ len++; ++ pEvent->Length = len; ++ ++ /* total tx event length + EventCode length + sizeof(length) */ ++ tx_event_length = pEvent->Length + 2; ++ ++ status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); ++ return status; ++ /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ ++ } ++} ++ ++u8 rtw_btcoex_parse_HCI_BT_abnormal_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) ++{ ++ u8 localBuf[6] = ""; ++ u8 *pRetPar; ++ u8 len = 0, tx_event_length = 0; ++ rtw_HCI_event *pEvent; ++ RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; ++ ++ { ++ pEvent = (rtw_HCI_event *)(&localBuf[0]); ++ ++ ++ pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; ++ pEvent->Data[0] = 0x1; /* packet # */ ++ pEvent->Data[1] = HCIOPCODELOW(HCI_BT_ABNORMAL_NOTIFY, OGF_EXTENSION); ++ pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_ABNORMAL_NOTIFY, OGF_EXTENSION); ++ len = len + 3; ++ ++ /* Return parameters starts from here */ ++ pRetPar = &pEvent->Data[len]; ++ pRetPar[0] = status; /* status */ ++ ++ len++; ++ pEvent->Length = len; ++ ++ /* total tx event length + EventCode length + sizeof(length) */ ++ tx_event_length = pEvent->Length + 2; ++ ++ status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); ++ return status; ++ /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ ++ } ++} ++ ++u8 rtw_btcoex_parse_HCI_query_RF_status_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) ++{ ++ u8 localBuf[6] = ""; ++ u8 *pRetPar; ++ u8 len = 0, tx_event_length = 0; ++ rtw_HCI_event *pEvent; ++ RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; ++ ++ { ++ pEvent = (rtw_HCI_event *)(&localBuf[0]); ++ ++ ++ pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; ++ pEvent->Data[0] = 0x1; /* packet # */ ++ pEvent->Data[1] = HCIOPCODELOW(HCI_QUERY_RF_STATUS, OGF_EXTENSION); ++ pEvent->Data[2] = HCIOPCODEHIGHT(HCI_QUERY_RF_STATUS, OGF_EXTENSION); ++ len = len + 3; ++ ++ /* Return parameters starts from here */ ++ pRetPar = &pEvent->Data[len]; ++ pRetPar[0] = status; /* status */ ++ ++ len++; ++ pEvent->Length = len; ++ ++ /* total tx event length + EventCode length + sizeof(length) */ ++ tx_event_length = pEvent->Length + 2; ++ ++ status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); ++ return status; ++ /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ ++ } ++} ++ ++/***************************************** ++* HCI cmd format : ++*| 15 - 0 | ++*| OPcode (OCF|OGF<<10) | ++*| 15 - 8 |7 - 0 | ++*|Cmd para |Cmd para Length | ++*|Cmd para...... | ++******************************************/ ++ ++/* bit 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ++ * | OCF | OGF | */ ++void rtw_btcoex_parse_hci_extend_cmd(_adapter *padapter, u8 *pcmd, u16 len, const u16 hci_OCF) ++{ ++ ++ RTW_INFO("%s: OCF: %x\n", __func__, hci_OCF); ++ switch (hci_OCF) { ++ case HCI_EXTENSION_VERSION_NOTIFY: ++ RTW_INFO("HCI_EXTENSION_VERSION_NOTIFY\n"); ++ rtw_btcoex_parse_HCI_Ver_notify_cmd(padapter, pcmd, len); ++ break; ++ case HCI_LINK_STATUS_NOTIFY: ++ RTW_INFO("HCI_LINK_STATUS_NOTIFY\n"); ++ rtw_btcoex_parse_HCI_link_status_notify_cmd(padapter, pcmd, len); ++ break; ++ case HCI_BT_OPERATION_NOTIFY: ++ /* only for 8723a 2ant */ ++ RTW_INFO("HCI_BT_OPERATION_NOTIFY\n"); ++ rtw_btcoex_parse_HCI_BT_operation_notify_cmd(padapter, pcmd, len); ++ /* */ ++ break; ++ case HCI_ENABLE_WIFI_SCAN_NOTIFY: ++ RTW_INFO("HCI_ENABLE_WIFI_SCAN_NOTIFY\n"); ++ rtw_btcoex_parse_WIFI_scan_notify_cmd(padapter, pcmd, len); ++ break; ++ case HCI_QUERY_RF_STATUS: ++ /* only for 8723b 2ant */ ++ RTW_INFO("HCI_QUERY_RF_STATUS\n"); ++ rtw_btcoex_parse_HCI_query_RF_status_cmd(padapter, pcmd, len); ++ break; ++ case HCI_BT_ABNORMAL_NOTIFY: ++ RTW_INFO("HCI_BT_ABNORMAL_NOTIFY\n"); ++ rtw_btcoex_parse_HCI_BT_abnormal_notify_cmd(padapter, pcmd, len); ++ break; ++ case HCI_BT_INFO_NOTIFY: ++ RTW_INFO("HCI_BT_INFO_NOTIFY\n"); ++ rtw_btcoex_parse_BT_info_notify_cmd(padapter, pcmd, len); ++ break; ++ case HCI_BT_COEX_NOTIFY: ++ RTW_INFO("HCI_BT_COEX_NOTIFY\n"); ++ rtw_btcoex_parse_HCI_BT_coex_notify_cmd(padapter, pcmd, len); ++ break; ++ case HCI_BT_PATCH_VERSION_NOTIFY: ++ RTW_INFO("HCI_BT_PATCH_VERSION_NOTIFY\n"); ++ rtw_btcoex_parse_BT_patch_ver_info_cmd(padapter, pcmd, len); ++ break; ++ case HCI_BT_AFH_MAP_NOTIFY: ++ RTW_INFO("HCI_BT_AFH_MAP_NOTIFY\n"); ++ rtw_btcoex_parse_BT_AFH_MAP_notify_cmd(padapter, pcmd, len); ++ break; ++ case HCI_BT_REGISTER_VALUE_NOTIFY: ++ RTW_INFO("HCI_BT_REGISTER_VALUE_NOTIFY\n"); ++ rtw_btcoex_parse_BT_register_val_notify_cmd(padapter, pcmd, len); ++ break; ++ default: ++ RTW_INFO("ERROR!!! Unknown OCF: %x\n", hci_OCF); ++ break; ++ ++ } ++} ++ ++void rtw_btcoex_parse_hci_cmd(_adapter *padapter, u8 *pcmd, u16 len) ++{ ++ u16 opcode = pcmd[0] | pcmd[1] << 8; ++ u16 hci_OGF = HCI_OGF(opcode); ++ u16 hci_OCF = HCI_OCF(opcode); ++ u8 cmdlen = len - 3; ++ u8 pare_len = pcmd[2]; ++ ++ RTW_INFO("%s OGF: %x,OCF: %x\n", __func__, hci_OGF, hci_OCF); ++ switch (hci_OGF) { ++ case OGF_EXTENSION: ++ RTW_INFO("HCI_EXTENSION_CMD_OGF\n"); ++ rtw_btcoex_parse_hci_extend_cmd(padapter, &pcmd[3], cmdlen, hci_OCF); ++ break; ++ default: ++ RTW_INFO("Other OGF: %x\n", hci_OGF); ++ break; ++ } ++} ++ ++u16 rtw_btcoex_parse_recv_data(u8 *msg, u8 msg_size) ++{ ++ u8 cmp_msg1[32] = attend_ack; ++ u8 cmp_msg2[32] = leave_ack; ++ u8 cmp_msg3[32] = bt_leave; ++ u8 cmp_msg4[32] = invite_req; ++ u8 cmp_msg5[32] = attend_req; ++ u8 cmp_msg6[32] = invite_rsp; ++ u8 res = OTHER; ++ ++ if (_rtw_memcmp(cmp_msg1, msg, msg_size) == _TRUE) { ++ /*RTW_INFO("%s, msg:%s\n",__func__,msg);*/ ++ res = RX_ATTEND_ACK; ++ } else if (_rtw_memcmp(cmp_msg2, msg, msg_size) == _TRUE) { ++ /*RTW_INFO("%s, msg:%s\n",__func__,msg);*/ ++ res = RX_LEAVE_ACK; ++ } else if (_rtw_memcmp(cmp_msg3, msg, msg_size) == _TRUE) { ++ /*RTW_INFO("%s, msg:%s\n",__func__,msg);*/ ++ res = RX_BT_LEAVE; ++ } else if (_rtw_memcmp(cmp_msg4, msg, msg_size) == _TRUE) { ++ /*RTW_INFO("%s, msg:%s\n",__func__,msg);*/ ++ res = RX_INVITE_REQ; ++ } else if (_rtw_memcmp(cmp_msg5, msg, msg_size) == _TRUE) ++ res = RX_ATTEND_REQ; ++ else if (_rtw_memcmp(cmp_msg6, msg, msg_size) == _TRUE) ++ res = RX_INVITE_RSP; ++ else { ++ /*RTW_INFO("%s, %s\n", __func__, msg);*/ ++ res = OTHER; ++ } ++ ++ /*RTW_INFO("%s, res:%d\n", __func__, res);*/ ++ ++ return res; ++} ++ ++void rtw_btcoex_recvmsgbysocket(void *data) ++{ ++ u8 recv_data[255]; ++ u8 tx_msg[255] = leave_ack; ++ u32 len = 0; ++ u16 recv_length = 0; ++ u16 parse_res = 0; ++#if 0 ++ u8 para_len = 0, polling_enable = 0, poling_interval = 0, reason = 0, btinfo_len = 0; ++ u8 btinfo[BT_INFO_LEN] = {0}; ++#endif ++ ++ struct bt_coex_info *pcoex_info = NULL; ++ struct sock *sk = NULL; ++ struct sk_buff *skb = NULL; ++ ++ /*RTW_INFO("%s\n",__func__);*/ ++ ++ if (pbtcoexadapter == NULL) { ++ RTW_INFO("%s: btcoexadapter NULL!\n", __func__); ++ return; ++ } ++ ++ pcoex_info = &pbtcoexadapter->coex_info; ++ sk = pcoex_info->sk_store; ++ ++ if (sk == NULL) { ++ RTW_INFO("%s: critical error when receive socket data!\n", __func__); ++ return; ++ } ++ ++ len = skb_queue_len(&sk->sk_receive_queue); ++ while (len > 0) { ++ skb = skb_dequeue(&sk->sk_receive_queue); ++ ++ /*important: cut the udp header from skb->data! header length is 8 byte*/ ++ recv_length = skb->len - 8; ++ _rtw_memset(recv_data, 0, sizeof(recv_data)); ++ _rtw_memcpy(recv_data, skb->data + 8, recv_length); ++ ++ parse_res = rtw_btcoex_parse_recv_data(recv_data, recv_length); ++#if 0 ++ if (RX_ATTEND_ACK == parse_res) { ++ /* attend ack */ ++ pcoex_info->BT_attend = _TRUE; ++ RTW_INFO("RX_ATTEND_ACK!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); ++ } else if (RX_ATTEND_REQ == parse_res) { ++ /* attend req from BT */ ++ pcoex_info->BT_attend = _TRUE; ++ RTW_INFO("RX_BT_ATTEND_REQ!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); ++ rtw_btcoex_sendmsgbysocket(pbtcoexadapter, attend_ack, sizeof(attend_ack), _FALSE); ++ } else if (RX_INVITE_REQ == parse_res) { ++ /* invite req from BT */ ++ pcoex_info->BT_attend = _TRUE; ++ RTW_INFO("RX_INVITE_REQ!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); ++ rtw_btcoex_sendmsgbysocket(pbtcoexadapter, invite_rsp, sizeof(invite_rsp), _FALSE); ++ } else if (RX_INVITE_RSP == parse_res) { ++ /* invite rsp */ ++ pcoex_info->BT_attend = _TRUE; ++ RTW_INFO("RX_INVITE_RSP!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); ++ } else if (RX_LEAVE_ACK == parse_res) { ++ /* mean BT know wifi will leave */ ++ pcoex_info->BT_attend = _FALSE; ++ RTW_INFO("RX_LEAVE_ACK!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); ++ } else if (RX_BT_LEAVE == parse_res) { ++ /* BT leave */ ++ rtw_btcoex_sendmsgbysocket(pbtcoexadapter, leave_ack, sizeof(leave_ack), _FALSE); /* no ack */ ++ pcoex_info->BT_attend = _FALSE; ++ RTW_INFO("RX_BT_LEAVE!sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); ++ } else { ++ /* todo: check if recv data are really hci cmds */ ++ if (_TRUE == pcoex_info->BT_attend) ++ rtw_btcoex_parse_hci_cmd(pbtcoexadapter, recv_data, recv_length); ++ } ++#endif ++ switch (parse_res) { ++ case RX_ATTEND_ACK: ++ /* attend ack */ ++ pcoex_info->BT_attend = _TRUE; ++ RTW_INFO("RX_ATTEND_ACK!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); ++ rtw_btcoex_pta_off_on_notify(pbtcoexadapter, pcoex_info->BT_attend); ++ break; ++ ++ case RX_ATTEND_REQ: ++ pcoex_info->BT_attend = _TRUE; ++ RTW_INFO("RX_BT_ATTEND_REQ!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); ++ rtw_btcoex_sendmsgbysocket(pbtcoexadapter, attend_ack, sizeof(attend_ack), _FALSE); ++ rtw_btcoex_pta_off_on_notify(pbtcoexadapter, pcoex_info->BT_attend); ++ break; ++ ++ case RX_INVITE_REQ: ++ /* invite req from BT */ ++ pcoex_info->BT_attend = _TRUE; ++ RTW_INFO("RX_INVITE_REQ!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); ++ rtw_btcoex_sendmsgbysocket(pbtcoexadapter, invite_rsp, sizeof(invite_rsp), _FALSE); ++ rtw_btcoex_pta_off_on_notify(pbtcoexadapter, pcoex_info->BT_attend); ++ break; ++ ++ case RX_INVITE_RSP: ++ /*invite rsp*/ ++ pcoex_info->BT_attend = _TRUE; ++ RTW_INFO("RX_INVITE_RSP!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); ++ rtw_btcoex_pta_off_on_notify(pbtcoexadapter, pcoex_info->BT_attend); ++ break; ++ ++ case RX_LEAVE_ACK: ++ /* mean BT know wifi will leave */ ++ pcoex_info->BT_attend = _FALSE; ++ RTW_INFO("RX_LEAVE_ACK!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); ++ rtw_btcoex_pta_off_on_notify(pbtcoexadapter, pcoex_info->BT_attend); ++ break; ++ ++ case RX_BT_LEAVE: ++ /* BT leave */ ++ rtw_btcoex_sendmsgbysocket(pbtcoexadapter, leave_ack, sizeof(leave_ack), _FALSE); /* no ack */ ++ pcoex_info->BT_attend = _FALSE; ++ RTW_INFO("RX_BT_LEAVE!sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); ++ rtw_btcoex_pta_off_on_notify(pbtcoexadapter, pcoex_info->BT_attend); ++ break; ++ ++ default: ++ if (_TRUE == pcoex_info->BT_attend) ++ rtw_btcoex_parse_hci_cmd(pbtcoexadapter, recv_data, recv_length); ++ else ++ RTW_INFO("ERROR!! BT is UP\n"); ++ break; ++ ++ } ++ ++ len--; ++ kfree_skb(skb); ++ } ++} ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0)) ++ void rtw_btcoex_recvmsg_init(struct sock *sk_in, s32 bytes) ++#else ++ void rtw_btcoex_recvmsg_init(struct sock *sk_in) ++#endif ++{ ++ struct bt_coex_info *pcoex_info = NULL; ++ ++ if (pbtcoexadapter == NULL) { ++ RTW_INFO("%s: btcoexadapter NULL\n", __func__); ++ return; ++ } ++ pcoex_info = &pbtcoexadapter->coex_info; ++ pcoex_info->sk_store = sk_in; ++ if (pcoex_info->btcoex_wq != NULL) ++ queue_delayed_work(pcoex_info->btcoex_wq, &pcoex_info->recvmsg_work, 0); ++ else ++ RTW_INFO("%s: BTCOEX workqueue NULL\n", __func__); ++} ++ ++u8 rtw_btcoex_sendmsgbysocket(_adapter *padapter, u8 *msg, u8 msg_size, bool force) ++{ ++ u8 error; ++ struct msghdr udpmsg; ++#ifdef set_fs ++ mm_segment_t oldfs; ++#endif ++ struct iovec iov; ++ struct bt_coex_info *pcoex_info = &padapter->coex_info; ++ ++ /* RTW_INFO("%s: msg:%s, force:%s\n", __func__, msg, force == _TRUE?"TRUE":"FALSE"); */ ++ if (_FALSE == force) { ++ if (_FALSE == pcoex_info->BT_attend) { ++ RTW_INFO("TX Blocked: WiFi-BT disconnected\n"); ++ return _FAIL; ++ } ++ } ++ ++ iov.iov_base = (void *)msg; ++ iov.iov_len = msg_size; ++ udpmsg.msg_name = &pcoex_info->bt_sockaddr; ++ udpmsg.msg_namelen = sizeof(struct sockaddr_in); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) ++ /* referece:sock_xmit in kernel code ++ * WRITE for sock_sendmsg, READ for sock_recvmsg ++ * third parameter for msg_iovlen ++ * last parameter for iov_len ++ */ ++ iov_iter_init(&udpmsg.msg_iter, WRITE, &iov, 1, msg_size); ++#else ++ udpmsg.msg_iov = &iov; ++ udpmsg.msg_iovlen = 1; ++#endif ++ udpmsg.msg_control = NULL; ++ udpmsg.msg_controllen = 0; ++ udpmsg.msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL; ++#ifdef set_fs ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++#endif ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) ++ error = sock_sendmsg(pcoex_info->udpsock, &udpmsg); ++#else ++ error = sock_sendmsg(pcoex_info->udpsock, &udpmsg, msg_size); ++#endif ++#ifdef set_fs ++ set_fs(oldfs); ++#endif ++ if (error < 0) { ++ RTW_INFO("Error when sendimg msg, error:%d\n", error); ++ return _FAIL; ++ } else ++ return _SUCCESS; ++} ++ ++u8 rtw_btcoex_create_kernel_socket(_adapter *padapter) ++{ ++ s8 kernel_socket_err; ++ u8 tx_msg[255] = attend_req; ++ struct bt_coex_info *pcoex_info = &padapter->coex_info; ++ s32 sock_reuse = 1; ++ u8 status = _FAIL; ++ ++ RTW_INFO("%s CONNECT_PORT %d\n", __func__, CONNECT_PORT); ++ ++ if (NULL == pcoex_info) { ++ RTW_INFO("coex_info: NULL\n"); ++ status = _FAIL; ++ } ++ ++ kernel_socket_err = sock_create(PF_INET, SOCK_DGRAM, 0, &pcoex_info->udpsock); ++ ++ if (kernel_socket_err < 0) { ++ RTW_INFO("Error during creation of socket error:%d\n", kernel_socket_err); ++ status = _FAIL; ++ } else { ++ _rtw_memset(&(pcoex_info->wifi_sockaddr), 0, sizeof(pcoex_info->wifi_sockaddr)); ++ pcoex_info->wifi_sockaddr.sin_family = AF_INET; ++ pcoex_info->wifi_sockaddr.sin_port = htons(CONNECT_PORT); ++ pcoex_info->wifi_sockaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); ++ ++ _rtw_memset(&(pcoex_info->bt_sockaddr), 0, sizeof(pcoex_info->bt_sockaddr)); ++ pcoex_info->bt_sockaddr.sin_family = AF_INET; ++ pcoex_info->bt_sockaddr.sin_port = htons(CONNECT_PORT_BT); ++ pcoex_info->bt_sockaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); ++ ++ pcoex_info->sk_store = NULL; ++ kernel_socket_err = pcoex_info->udpsock->ops->bind(pcoex_info->udpsock, (struct sockaddr *)&pcoex_info->wifi_sockaddr, ++ sizeof(pcoex_info->wifi_sockaddr)); ++ if (kernel_socket_err == 0) { ++ RTW_INFO("binding socket success\n"); ++ pcoex_info->udpsock->sk->sk_data_ready = rtw_btcoex_recvmsg_init; ++ pcoex_info->sock_open |= KERNEL_SOCKET_OK; ++ pcoex_info->BT_attend = _FALSE; ++ RTW_INFO("WIFI sending attend_req\n"); ++ rtw_btcoex_sendmsgbysocket(padapter, attend_req, sizeof(attend_req), _TRUE); ++ status = _SUCCESS; ++ } else { ++ pcoex_info->BT_attend = _FALSE; ++ sock_release(pcoex_info->udpsock); /* bind fail release socket */ ++ RTW_INFO("Error binding socket: %d\n", kernel_socket_err); ++ status = _FAIL; ++ } ++ ++ } ++ ++ return status; ++} ++ ++void rtw_btcoex_close_kernel_socket(_adapter *padapter) ++{ ++ struct bt_coex_info *pcoex_info = &padapter->coex_info; ++ if (pcoex_info->sock_open & KERNEL_SOCKET_OK) { ++ RTW_INFO("release kernel socket\n"); ++ sock_release(pcoex_info->udpsock); ++ pcoex_info->sock_open &= ~(KERNEL_SOCKET_OK); ++ if (_TRUE == pcoex_info->BT_attend) ++ pcoex_info->BT_attend = _FALSE; ++ ++ RTW_INFO("sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); ++ } ++} ++ ++void rtw_btcoex_init_socket(_adapter *padapter) ++{ ++ ++ u8 is_invite = _FALSE; ++ struct bt_coex_info *pcoex_info = &padapter->coex_info; ++ RTW_INFO("%s\n", __func__); ++ if (_FALSE == pcoex_info->is_exist) { ++ _rtw_memset(pcoex_info, 0, sizeof(struct bt_coex_info)); ++ pcoex_info->btcoex_wq = create_workqueue("BTCOEX"); ++ INIT_DELAYED_WORK(&pcoex_info->recvmsg_work, ++ (void *)rtw_btcoex_recvmsgbysocket); ++ pbtcoexadapter = padapter; ++ /* We expect BT is off if BT don't send ack to wifi */ ++ RTW_INFO("We expect BT is off if BT send ack to wifi\n"); ++ rtw_btcoex_pta_off_on_notify(pbtcoexadapter, _FALSE); ++ if (rtw_btcoex_create_kernel_socket(padapter) == _SUCCESS) ++ pcoex_info->is_exist = _TRUE; ++ else { ++ pcoex_info->is_exist = _FALSE; ++ pbtcoexadapter = NULL; ++ } ++ ++ RTW_INFO("%s: pbtcoexadapter:%p, coex_info->is_exist: %s\n" ++ , __func__, pbtcoexadapter, pcoex_info->is_exist == _TRUE ? "TRUE" : "FALSE"); ++ } ++} ++ ++void rtw_btcoex_close_socket(_adapter *padapter) ++{ ++ struct bt_coex_info *pcoex_info = &padapter->coex_info; ++ ++ RTW_INFO("%s--coex_info->is_exist: %s, pcoex_info->BT_attend:%s\n" ++ , __func__, pcoex_info->is_exist == _TRUE ? "TRUE" : "FALSE", pcoex_info->BT_attend == _TRUE ? "TRUE" : "FALSE"); ++ ++ if (_TRUE == pcoex_info->is_exist) { ++ if (_TRUE == pcoex_info->BT_attend) { ++ /*inform BT wifi leave*/ ++ rtw_btcoex_sendmsgbysocket(padapter, wifi_leave, sizeof(wifi_leave), _FALSE); ++ msleep(50); ++ } ++ ++ if (pcoex_info->btcoex_wq != NULL) { ++ flush_workqueue(pcoex_info->btcoex_wq); ++ destroy_workqueue(pcoex_info->btcoex_wq); ++ } ++ ++ rtw_btcoex_close_kernel_socket(padapter); ++ pbtcoexadapter = NULL; ++ pcoex_info->is_exist = _FALSE; ++ } ++} ++ ++void rtw_btcoex_dump_tx_msg(u8 *tx_msg, u8 len, u8 *msg_name) ++{ ++ u8 i = 0; ++ RTW_INFO("======> Msg name: %s\n", msg_name); ++ for (i = 0; i < len; i++) ++ printk("%02x ", tx_msg[i]); ++ printk("\n"); ++ RTW_INFO("Msg name: %s <======\n", msg_name); ++} ++ ++/* Porting from Windows team */ ++void rtw_btcoex_SendEventExtBtCoexControl(PADAPTER padapter, u8 bNeedDbgRsp, u8 dataLen, void *pData) ++{ ++ u8 len = 0, tx_event_length = 0; ++ u8 localBuf[32] = ""; ++ u8 *pRetPar; ++ u8 opCode = 0; ++ u8 *pInBuf = (pu1Byte)pData; ++ u8 *pOpCodeContent; ++ rtw_HCI_event *pEvent; ++ ++ opCode = pInBuf[0]; ++ ++ RTW_INFO("%s, OPCode:%02x\n", __func__, opCode); ++ ++ pEvent = (rtw_HCI_event *)(&localBuf[0]); ++ ++ /* len += bthci_ExtensionEventHeaderRtk(&localBuf[0], */ ++ /* HCI_EVENT_EXT_BT_COEX_CONTROL); */ ++ pEvent->EventCode = HCI_EVENT_EXTENSION_RTK; ++ pEvent->Data[0] = HCI_EVENT_EXT_BT_COEX_CONTROL; /* extension event code */ ++ len++; ++ ++ /* Return parameters starts from here */ ++ pRetPar = &pEvent->Data[len]; ++ _rtw_memcpy(&pRetPar[0], pData, dataLen); ++ ++ len += dataLen; ++ ++ pEvent->Length = len; ++ ++ /* total tx event length + EventCode length + sizeof(length) */ ++ tx_event_length = pEvent->Length + 2; ++#if 0 ++ rtw_btcoex_dump_tx_msg((u8 *)pEvent, tx_event_length, "BT COEX CONTROL", _FALSE); ++#endif ++ rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); ++ ++} ++ ++/* Porting from Windows team */ ++void rtw_btcoex_SendEventExtBtInfoControl(PADAPTER padapter, u8 dataLen, void *pData) ++{ ++ rtw_HCI_event *pEvent; ++ u8 *pRetPar; ++ u8 len = 0, tx_event_length = 0; ++ u8 localBuf[32] = ""; ++ ++ struct bt_coex_info *pcoex_info = &padapter->coex_info; ++ PBT_MGNT pBtMgnt = &pcoex_info->BtMgnt; ++ ++ /* RTW_INFO("%s\n",__func__);*/ ++ if (pBtMgnt->ExtConfig.HCIExtensionVer < 4) { /* not support */ ++ RTW_INFO("ERROR: HCIExtensionVer = %d, HCIExtensionVer<4 !!!!\n", pBtMgnt->ExtConfig.HCIExtensionVer); ++ return; ++ } ++ ++ pEvent = (rtw_HCI_event *)(&localBuf[0]); ++ ++ /* len += bthci_ExtensionEventHeaderRtk(&localBuf[0], */ ++ /* HCI_EVENT_EXT_BT_INFO_CONTROL); */ ++ pEvent->EventCode = HCI_EVENT_EXTENSION_RTK; ++ pEvent->Data[0] = HCI_EVENT_EXT_BT_INFO_CONTROL; /* extension event code */ ++ len++; ++ ++ /* Return parameters starts from here */ ++ pRetPar = &pEvent->Data[len]; ++ _rtw_memcpy(&pRetPar[0], pData, dataLen); ++ ++ len += dataLen; ++ ++ pEvent->Length = len; ++ ++ /* total tx event length + EventCode length + sizeof(length) */ ++ tx_event_length = pEvent->Length + 2; ++#if 0 ++ rtw_btcoex_dump_tx_msg((u8 *)pEvent, tx_event_length, "BT INFO CONTROL"); ++#endif ++ rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); ++ ++} ++ ++void rtw_btcoex_SendScanNotify(PADAPTER padapter, u8 scanType) ++{ ++ u8 len = 0, tx_event_length = 0; ++ u8 localBuf[7] = ""; ++ u8 *pRetPar; ++ u8 *pu1Temp; ++ rtw_HCI_event *pEvent; ++ struct bt_coex_info *pcoex_info = &padapter->coex_info; ++ PBT_MGNT pBtMgnt = &pcoex_info->BtMgnt; ++ ++ /* if(!pBtMgnt->BtOperationOn) ++ * return; */ ++ ++ pEvent = (rtw_HCI_event *)(&localBuf[0]); ++ ++ /* len += bthci_ExtensionEventHeaderRtk(&localBuf[0], ++ * HCI_EVENT_EXT_WIFI_SCAN_NOTIFY); */ ++ ++ pEvent->EventCode = HCI_EVENT_EXTENSION_RTK; ++ pEvent->Data[0] = HCI_EVENT_EXT_WIFI_SCAN_NOTIFY; /* extension event code */ ++ len++; ++ ++ /* Return parameters starts from here */ ++ /* pRetPar = &PPacketIrpEvent->Data[len]; */ ++ /* pu1Temp = (u8 *)&pRetPar[0]; */ ++ /* *pu1Temp = scanType; */ ++ pEvent->Data[len] = scanType; ++ len += 1; ++ ++ pEvent->Length = len; ++ ++ /* total tx event length + EventCode length + sizeof(length) */ ++ tx_event_length = pEvent->Length + 2; ++#if 0 ++ rtw_btcoex_dump_tx_msg((u8 *)pEvent, tx_event_length, "WIFI SCAN OPERATION"); ++#endif ++ rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); ++} ++#endif /* CONFIG_BT_COEXIST_SOCKET_TRX */ ++#endif /* CONFIG_BT_COEXIST */ ++ ++void rtw_btcoex_set_ant_info(PADAPTER padapter) ++{ ++#ifdef CONFIG_BT_COEXIST ++ PHAL_DATA_TYPE hal = GET_HAL_DATA(padapter); ++ ++ if (hal->EEPROMBluetoothCoexist == _TRUE) { ++ u8 bMacPwrCtrlOn = _FALSE; ++ ++ rtw_btcoex_AntInfoSetting(padapter); ++ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ if (bMacPwrCtrlOn == _TRUE) ++ rtw_btcoex_PowerOnSetting(padapter); ++ } ++ else ++#endif ++ rtw_btcoex_wifionly_AntInfoSetting(padapter); ++} ++ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_btcoex_wifionly.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_btcoex_wifionly.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_btcoex_wifionly.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_btcoex_wifionly.c 2021-03-07 18:16:17.018954351 +0200 +@@ -0,0 +1,47 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2013 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++#include ++#include ++#include ++ ++void rtw_btcoex_wifionly_switchband_notify(PADAPTER padapter) ++{ ++ hal_btcoex_wifionly_switchband_notify(padapter); ++} ++ ++void rtw_btcoex_wifionly_scan_notify(PADAPTER padapter) ++{ ++ hal_btcoex_wifionly_scan_notify(padapter); ++} ++ ++void rtw_btcoex_wifionly_connect_notify(PADAPTER padapter) ++{ ++ hal_btcoex_wifionly_connect_notify(padapter); ++} ++ ++void rtw_btcoex_wifionly_hw_config(PADAPTER padapter) ++{ ++ hal_btcoex_wifionly_hw_config(padapter); ++} ++ ++void rtw_btcoex_wifionly_initialize(PADAPTER padapter) ++{ ++ hal_btcoex_wifionly_initlizevariables(padapter); ++} ++ ++void rtw_btcoex_wifionly_AntInfoSetting(PADAPTER padapter) ++{ ++ hal_btcoex_wifionly_AntInfoSetting(padapter); ++} +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_bt_mp.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_bt_mp.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_bt_mp.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_bt_mp.c 2021-03-07 18:16:17.017954304 +0200 @@ -0,0 +1,1575 @@ +/****************************************************************************** + * @@ -25815,1832 +24713,9 @@ index 000000000..9b4fc2432 +} + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_btcoex.c linux-5.8/3rdparty/rtl8812au/core/rtw_btcoex.c -new file mode 100644 -index 000000000..d5b89bdc3 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_btcoex.c -@@ -0,0 +1,1762 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2013 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+#include -+#include -+#ifdef CONFIG_BT_COEXIST -+#include -+ -+void rtw_btcoex_Initialize(PADAPTER padapter) -+{ -+ hal_btcoex_Initialize(padapter); -+} -+ -+void rtw_btcoex_PowerOnSetting(PADAPTER padapter) -+{ -+ hal_btcoex_PowerOnSetting(padapter); -+} -+ -+void rtw_btcoex_AntInfoSetting(PADAPTER padapter) -+{ -+ hal_btcoex_AntInfoSetting(padapter); -+} -+ -+void rtw_btcoex_PowerOffSetting(PADAPTER padapter) -+{ -+ hal_btcoex_PowerOffSetting(padapter); -+} -+ -+void rtw_btcoex_PreLoadFirmware(PADAPTER padapter) -+{ -+ hal_btcoex_PreLoadFirmware(padapter); -+} -+ -+void rtw_btcoex_HAL_Initialize(PADAPTER padapter, u8 bWifiOnly) -+{ -+ hal_btcoex_InitHwConfig(padapter, bWifiOnly); -+} -+ -+void rtw_btcoex_IpsNotify(PADAPTER padapter, u8 type) -+{ -+ PHAL_DATA_TYPE pHalData; -+ -+ pHalData = GET_HAL_DATA(padapter); -+ if (_FALSE == pHalData->EEPROMBluetoothCoexist) -+ return; -+ -+ hal_btcoex_IpsNotify(padapter, type); -+} -+ -+void rtw_btcoex_LpsNotify(PADAPTER padapter, u8 type) -+{ -+ PHAL_DATA_TYPE pHalData; -+ -+ pHalData = GET_HAL_DATA(padapter); -+ if (_FALSE == pHalData->EEPROMBluetoothCoexist) -+ return; -+ -+ hal_btcoex_LpsNotify(padapter, type); -+} -+ -+void rtw_btcoex_ScanNotify(PADAPTER padapter, u8 type) -+{ -+ PHAL_DATA_TYPE pHalData; -+#ifdef CONFIG_BT_COEXIST_SOCKET_TRX -+ struct bt_coex_info *pcoex_info = &padapter->coex_info; -+ PBT_MGNT pBtMgnt = &pcoex_info->BtMgnt; -+#endif /* CONFIG_BT_COEXIST_SOCKET_TRX */ -+ -+ pHalData = GET_HAL_DATA(padapter); -+ if (_FALSE == pHalData->EEPROMBluetoothCoexist) -+ return; -+ -+ if (_FALSE == type) { -+ #ifdef CONFIG_CONCURRENT_MODE -+ if (rtw_mi_buddy_check_fwstate(padapter, WIFI_SITE_MONITOR)) -+ return; -+ #endif -+ -+ if (DEV_MGMT_TX_NUM(adapter_to_dvobj(padapter)) -+ || DEV_ROCH_NUM(adapter_to_dvobj(padapter))) -+ return; -+ } -+ -+#ifdef CONFIG_BT_COEXIST_SOCKET_TRX -+ if (pBtMgnt->ExtConfig.bEnableWifiScanNotify) -+ rtw_btcoex_SendScanNotify(padapter, type); -+#endif /* CONFIG_BT_COEXIST_SOCKET_TRX */ -+ -+ hal_btcoex_ScanNotify(padapter, type); -+} -+ -+void rtw_btcoex_ConnectNotify(PADAPTER padapter, u8 action) -+{ -+ PHAL_DATA_TYPE pHalData; -+ -+ pHalData = GET_HAL_DATA(padapter); -+ if (_FALSE == pHalData->EEPROMBluetoothCoexist) -+ return; -+ -+#ifdef DBG_CONFIG_ERROR_RESET -+ if (_TRUE == rtw_hal_sreset_inprogress(padapter)) { -+ RTW_INFO(FUNC_ADPT_FMT ": [BTCoex] under reset, skip notify!\n", -+ FUNC_ADPT_ARG(padapter)); -+ return; -+ } -+#endif /* DBG_CONFIG_ERROR_RESET */ -+ -+#ifdef CONFIG_CONCURRENT_MODE -+ if (_FALSE == action) { -+ if (rtw_mi_buddy_check_fwstate(padapter, WIFI_UNDER_LINKING)) -+ return; -+ } -+#endif -+ -+ hal_btcoex_ConnectNotify(padapter, action); -+} -+ -+void rtw_btcoex_MediaStatusNotify(PADAPTER padapter, u8 mediaStatus) -+{ -+ PHAL_DATA_TYPE pHalData; -+ -+ pHalData = GET_HAL_DATA(padapter); -+ if (_FALSE == pHalData->EEPROMBluetoothCoexist) -+ return; -+ -+#ifdef DBG_CONFIG_ERROR_RESET -+ if (_TRUE == rtw_hal_sreset_inprogress(padapter)) { -+ RTW_INFO(FUNC_ADPT_FMT ": [BTCoex] under reset, skip notify!\n", -+ FUNC_ADPT_ARG(padapter)); -+ return; -+ } -+#endif /* DBG_CONFIG_ERROR_RESET */ -+ -+#ifdef CONFIG_CONCURRENT_MODE -+ if (RT_MEDIA_DISCONNECT == mediaStatus) { -+ if (rtw_mi_buddy_check_fwstate(padapter, WIFI_ASOC_STATE)) -+ return; -+ } -+#endif /* CONFIG_CONCURRENT_MODE */ -+ -+ if ((RT_MEDIA_CONNECT == mediaStatus) -+ && (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == _TRUE)) -+ rtw_hal_set_hwreg(padapter, HW_VAR_DL_RSVD_PAGE, NULL); -+ -+ hal_btcoex_MediaStatusNotify(padapter, mediaStatus); -+} -+ -+void rtw_btcoex_SpecialPacketNotify(PADAPTER padapter, u8 pktType) -+{ -+ PHAL_DATA_TYPE pHalData; -+ -+ pHalData = GET_HAL_DATA(padapter); -+ if (_FALSE == pHalData->EEPROMBluetoothCoexist) -+ return; -+ -+ hal_btcoex_SpecialPacketNotify(padapter, pktType); -+} -+ -+void rtw_btcoex_IQKNotify(PADAPTER padapter, u8 state) -+{ -+ PHAL_DATA_TYPE pHalData; -+ -+ pHalData = GET_HAL_DATA(padapter); -+ if (_FALSE == pHalData->EEPROMBluetoothCoexist) -+ return; -+ -+ hal_btcoex_IQKNotify(padapter, state); -+} -+ -+void rtw_btcoex_BtInfoNotify(PADAPTER padapter, u8 length, u8 *tmpBuf) -+{ -+ PHAL_DATA_TYPE pHalData; -+ -+ pHalData = GET_HAL_DATA(padapter); -+ if (_FALSE == pHalData->EEPROMBluetoothCoexist) -+ return; -+ -+ hal_btcoex_BtInfoNotify(padapter, length, tmpBuf); -+} -+ -+void rtw_btcoex_BtMpRptNotify(PADAPTER padapter, u8 length, u8 *tmpBuf) -+{ -+ PHAL_DATA_TYPE pHalData; -+ -+ pHalData = GET_HAL_DATA(padapter); -+ if (_FALSE == pHalData->EEPROMBluetoothCoexist) -+ return; -+ -+ if (padapter->registrypriv.mp_mode == 1) -+ return; -+ -+ hal_btcoex_BtMpRptNotify(padapter, length, tmpBuf); -+} -+ -+void rtw_btcoex_SuspendNotify(PADAPTER padapter, u8 state) -+{ -+ PHAL_DATA_TYPE pHalData; -+ -+ pHalData = GET_HAL_DATA(padapter); -+ if (_FALSE == pHalData->EEPROMBluetoothCoexist) -+ return; -+ -+ hal_btcoex_SuspendNotify(padapter, state); -+} -+ -+void rtw_btcoex_HaltNotify(PADAPTER padapter) -+{ -+ PHAL_DATA_TYPE pHalData; -+ u8 do_halt = 1; -+ -+ pHalData = GET_HAL_DATA(padapter); -+ if (_FALSE == pHalData->EEPROMBluetoothCoexist) -+ do_halt = 0; -+ -+ if (_FALSE == padapter->bup) { -+ RTW_INFO(FUNC_ADPT_FMT ": bup=%d Skip!\n", -+ FUNC_ADPT_ARG(padapter), padapter->bup); -+ do_halt = 0; -+ } -+ -+ if (rtw_is_surprise_removed(padapter)) { -+ RTW_INFO(FUNC_ADPT_FMT ": bSurpriseRemoved=%s Skip!\n", -+ FUNC_ADPT_ARG(padapter), rtw_is_surprise_removed(padapter) ? "True" : "False"); -+ do_halt = 0; -+ } -+ -+ hal_btcoex_HaltNotify(padapter, do_halt); -+} -+ -+void rtw_btcoex_switchband_notify(u8 under_scan, u8 band_type) -+{ -+ hal_btcoex_switchband_notify(under_scan, band_type); -+} -+ -+void rtw_btcoex_WlFwDbgInfoNotify(PADAPTER padapter, u8* tmpBuf, u8 length) -+{ -+ hal_btcoex_WlFwDbgInfoNotify(padapter, tmpBuf, length); -+} -+ -+void rtw_btcoex_rx_rate_change_notify(PADAPTER padapter, u8 is_data_frame, u8 rate_id) -+{ -+ hal_btcoex_rx_rate_change_notify(padapter, is_data_frame, rate_id); -+} -+ -+void rtw_btcoex_SwitchBtTRxMask(PADAPTER padapter) -+{ -+ hal_btcoex_SwitchBtTRxMask(padapter); -+} -+ -+void rtw_btcoex_Switch(PADAPTER padapter, u8 enable) -+{ -+ hal_btcoex_SetBTCoexist(padapter, enable); -+} -+ -+u8 rtw_btcoex_IsBtDisabled(PADAPTER padapter) -+{ -+ return hal_btcoex_IsBtDisabled(padapter); -+} -+ -+void rtw_btcoex_Handler(PADAPTER padapter) -+{ -+ PHAL_DATA_TYPE pHalData; -+ -+ pHalData = GET_HAL_DATA(padapter); -+ -+ if (_FALSE == pHalData->EEPROMBluetoothCoexist) -+ return; -+ -+ hal_btcoex_Hanlder(padapter); -+} -+ -+s32 rtw_btcoex_IsBTCoexRejectAMPDU(PADAPTER padapter) -+{ -+ s32 coexctrl; -+ -+ coexctrl = hal_btcoex_IsBTCoexRejectAMPDU(padapter); -+ -+ return coexctrl; -+} -+ -+s32 rtw_btcoex_IsBTCoexCtrlAMPDUSize(PADAPTER padapter) -+{ -+ s32 coexctrl; -+ -+ coexctrl = hal_btcoex_IsBTCoexCtrlAMPDUSize(padapter); -+ -+ return coexctrl; -+} -+ -+u32 rtw_btcoex_GetAMPDUSize(PADAPTER padapter) -+{ -+ u32 size; -+ -+ size = hal_btcoex_GetAMPDUSize(padapter); -+ -+ return size; -+} -+ -+void rtw_btcoex_SetManualControl(PADAPTER padapter, u8 manual) -+{ -+ if (_TRUE == manual) -+ hal_btcoex_SetManualControl(padapter, _TRUE); -+ else -+ hal_btcoex_SetManualControl(padapter, _FALSE); -+} -+ -+u8 rtw_btcoex_1Ant(PADAPTER padapter) -+{ -+ return hal_btcoex_1Ant(padapter); -+} -+ -+u8 rtw_btcoex_IsBtControlLps(PADAPTER padapter) -+{ -+ return hal_btcoex_IsBtControlLps(padapter); -+} -+ -+u8 rtw_btcoex_IsLpsOn(PADAPTER padapter) -+{ -+ return hal_btcoex_IsLpsOn(padapter); -+} -+ -+u8 rtw_btcoex_RpwmVal(PADAPTER padapter) -+{ -+ return hal_btcoex_RpwmVal(padapter); -+} -+ -+u8 rtw_btcoex_LpsVal(PADAPTER padapter) -+{ -+ return hal_btcoex_LpsVal(padapter); -+} -+ -+u32 rtw_btcoex_GetRaMask(PADAPTER padapter) -+{ -+ return hal_btcoex_GetRaMask(padapter); -+} -+ -+void rtw_btcoex_RecordPwrMode(PADAPTER padapter, u8 *pCmdBuf, u8 cmdLen) -+{ -+ hal_btcoex_RecordPwrMode(padapter, pCmdBuf, cmdLen); -+} -+ -+void rtw_btcoex_DisplayBtCoexInfo(PADAPTER padapter, u8 *pbuf, u32 bufsize) -+{ -+ hal_btcoex_DisplayBtCoexInfo(padapter, pbuf, bufsize); -+} -+ -+void rtw_btcoex_SetDBG(PADAPTER padapter, u32 *pDbgModule) -+{ -+ hal_btcoex_SetDBG(padapter, pDbgModule); -+} -+ -+u32 rtw_btcoex_GetDBG(PADAPTER padapter, u8 *pStrBuf, u32 bufSize) -+{ -+ return hal_btcoex_GetDBG(padapter, pStrBuf, bufSize); -+} -+ -+u8 rtw_btcoex_IncreaseScanDeviceNum(PADAPTER padapter) -+{ -+ return hal_btcoex_IncreaseScanDeviceNum(padapter); -+} -+ -+u8 rtw_btcoex_IsBtLinkExist(PADAPTER padapter) -+{ -+ return hal_btcoex_IsBtLinkExist(padapter); -+} -+ -+void rtw_btcoex_SetBtPatchVersion(PADAPTER padapter, u16 btHciVer, u16 btPatchVer) -+{ -+ hal_btcoex_SetBtPatchVersion(padapter, btHciVer, btPatchVer); -+} -+ -+void rtw_btcoex_SetHciVersion(PADAPTER padapter, u16 hciVersion) -+{ -+ hal_btcoex_SetHciVersion(padapter, hciVersion); -+} -+ -+void rtw_btcoex_StackUpdateProfileInfo(void) -+{ -+ hal_btcoex_StackUpdateProfileInfo(); -+} -+ -+void rtw_btcoex_pta_off_on_notify(PADAPTER padapter, u8 bBTON) -+{ -+ hal_btcoex_pta_off_on_notify(padapter, bBTON); -+} -+ -+#ifdef CONFIG_RF4CE_COEXIST -+void rtw_btcoex_SetRf4ceLinkState(PADAPTER padapter, u8 state) -+{ -+ hal_btcoex_set_rf4ce_link_state(state); -+} -+ -+u8 rtw_btcoex_GetRf4ceLinkState(PADAPTER padapter) -+{ -+ return hal_btcoex_get_rf4ce_link_state(); -+} -+#endif -+ -+/* ================================================== -+ * Below Functions are called by BT-Coex -+ * ================================================== */ -+void rtw_btcoex_rx_ampdu_apply(PADAPTER padapter) -+{ -+ rtw_rx_ampdu_apply(padapter); -+} -+ -+void rtw_btcoex_LPS_Enter(PADAPTER padapter) -+{ -+ struct pwrctrl_priv *pwrpriv; -+ u8 lpsVal; -+ -+ -+ pwrpriv = adapter_to_pwrctl(padapter); -+ -+ pwrpriv->bpower_saving = _TRUE; -+ lpsVal = rtw_btcoex_LpsVal(padapter); -+ rtw_set_ps_mode(padapter, PS_MODE_MIN, 0, lpsVal, "BTCOEX"); -+} -+ -+u8 rtw_btcoex_LPS_Leave(PADAPTER padapter) -+{ -+ struct pwrctrl_priv *pwrpriv; -+ -+ -+ pwrpriv = adapter_to_pwrctl(padapter); -+ -+ if (pwrpriv->pwr_mode != PS_MODE_ACTIVE) { -+ rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0, "BTCOEX"); -+ pwrpriv->bpower_saving = _FALSE; -+ } -+ -+ return _TRUE; -+} -+ -+u16 rtw_btcoex_btreg_read(PADAPTER padapter, u8 type, u16 addr, u32 *data) -+{ -+ return hal_btcoex_btreg_read(padapter, type, addr, data); -+} -+ -+u16 rtw_btcoex_btreg_write(PADAPTER padapter, u8 type, u16 addr, u16 val) -+{ -+ return hal_btcoex_btreg_write(padapter, type, addr, val); -+} -+ -+u8 rtw_btcoex_get_bt_coexist(PADAPTER padapter) -+{ -+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); -+ -+ return pHalData->EEPROMBluetoothCoexist; -+} -+ -+u8 rtw_btcoex_get_chip_type(PADAPTER padapter) -+{ -+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); -+ -+ return pHalData->EEPROMBluetoothType; -+} -+ -+u8 rtw_btcoex_get_pg_ant_num(PADAPTER padapter) -+{ -+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); -+ -+ return pHalData->EEPROMBluetoothAntNum == Ant_x2 ? 2 : 1; -+} -+ -+u8 rtw_btcoex_get_pg_single_ant_path(PADAPTER padapter) -+{ -+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); -+ -+ return pHalData->ant_path; -+} -+ -+u8 rtw_btcoex_get_pg_rfe_type(PADAPTER padapter) -+{ -+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); -+ -+ return pHalData->rfe_type; -+} -+ -+u8 rtw_btcoex_is_tfbga_package_type(PADAPTER padapter) -+{ -+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); -+ -+#ifdef CONFIG_RTL8723B -+ if ((pHalData->PackageType == PACKAGE_TFBGA79) || (pHalData->PackageType == PACKAGE_TFBGA80) -+ || (pHalData->PackageType == PACKAGE_TFBGA90)) -+ return _TRUE; -+#endif -+ -+ return _FALSE; -+} -+ -+u8 rtw_btcoex_get_ant_div_cfg(PADAPTER padapter) -+{ -+ PHAL_DATA_TYPE pHalData; -+ -+ pHalData = GET_HAL_DATA(padapter); -+ -+ return (pHalData->AntDivCfg == 0) ? _FALSE : _TRUE; -+} -+ -+/* ================================================== -+ * Below Functions are BT-Coex socket related function -+ * ================================================== */ -+ -+#ifdef CONFIG_BT_COEXIST_SOCKET_TRX -+_adapter *pbtcoexadapter; /* = NULL; */ /* do not initialise globals to 0 or NULL */ -+u8 rtw_btcoex_btinfo_cmd(_adapter *adapter, u8 *buf, u16 len) -+{ -+ struct cmd_obj *ph2c; -+ struct drvextra_cmd_parm *pdrvextra_cmd_parm; -+ u8 *btinfo; -+ struct cmd_priv *pcmdpriv = &adapter->cmdpriv; -+ u8 res = _SUCCESS; -+ -+ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); -+ if (ph2c == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ -+ pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); -+ if (pdrvextra_cmd_parm == NULL) { -+ rtw_mfree((u8 *)ph2c, sizeof(struct cmd_obj)); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ btinfo = rtw_zmalloc(len); -+ if (btinfo == NULL) { -+ rtw_mfree((u8 *)ph2c, sizeof(struct cmd_obj)); -+ rtw_mfree((u8 *)pdrvextra_cmd_parm, sizeof(struct drvextra_cmd_parm)); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ pdrvextra_cmd_parm->ec_id = BTINFO_WK_CID; -+ pdrvextra_cmd_parm->type = 0; -+ pdrvextra_cmd_parm->size = len; -+ pdrvextra_cmd_parm->pbuf = btinfo; -+ -+ _rtw_memcpy(btinfo, buf, len); -+ -+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); -+ -+ res = rtw_enqueue_cmd(pcmdpriv, ph2c); -+ -+exit: -+ return res; -+} -+ -+u8 rtw_btcoex_send_event_to_BT(_adapter *padapter, u8 status, u8 event_code, u8 opcode_low, u8 opcode_high, u8 *dbg_msg) -+{ -+ u8 localBuf[6] = ""; -+ u8 *pRetPar; -+ u8 len = 0, tx_event_length = 0; -+ rtw_HCI_event *pEvent; -+ -+ pEvent = (rtw_HCI_event *)(&localBuf[0]); -+ -+ pEvent->EventCode = event_code; -+ pEvent->Data[0] = 0x1; /* packet # */ -+ pEvent->Data[1] = opcode_low; -+ pEvent->Data[2] = opcode_high; -+ len = len + 3; -+ -+ /* Return parameters starts from here */ -+ pRetPar = &pEvent->Data[len]; -+ pRetPar[0] = status; /* status */ -+ -+ len++; -+ pEvent->Length = len; -+ -+ /* total tx event length + EventCode length + sizeof(length) */ -+ tx_event_length = pEvent->Length + 2; -+#if 0 -+ rtw_btcoex_dump_tx_msg((u8 *)pEvent, tx_event_length, dbg_msg); -+#endif -+ status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); -+ -+ return status; -+} -+ -+/* -+Ref: -+Realtek Wi-Fi Driver -+Host Controller Interface for -+Bluetooth 3.0 + HS V1.4 2013/02/07 -+ -+Window team code & BT team code -+ */ -+ -+ -+u8 rtw_btcoex_parse_BT_info_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) -+{ -+#define BT_INFO_LENGTH 8 -+ -+ u8 curPollEnable = pcmd[0]; -+ u8 curPollTime = pcmd[1]; -+ u8 btInfoReason = pcmd[2]; -+ u8 btInfoLen = pcmd[3]; -+ u8 btinfo[BT_INFO_LENGTH]; -+ -+ u8 localBuf[6] = ""; -+ u8 *pRetPar; -+ u8 len = 0, tx_event_length = 0; -+ RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; -+ rtw_HCI_event *pEvent; -+ -+ /* RTW_INFO("%s\n",__func__); -+ RTW_INFO("current Poll Enable: %d, currrent Poll Time: %d\n",curPollEnable,curPollTime); -+ RTW_INFO("BT Info reason: %d, BT Info length: %d\n",btInfoReason,btInfoLen); -+ RTW_INFO("%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n" -+ ,pcmd[4],pcmd[5],pcmd[6],pcmd[7],pcmd[8],pcmd[9],pcmd[10],pcmd[11]);*/ -+ -+ _rtw_memset(btinfo, 0, BT_INFO_LENGTH); -+ -+#if 1 -+ if (BT_INFO_LENGTH != btInfoLen) { -+ status = HCI_STATUS_INVALID_HCI_CMD_PARA_VALUE; -+ RTW_INFO("Error BT Info Length: %d\n", btInfoLen); -+ /* return _FAIL; */ -+ } else -+#endif -+ { -+ if (0x1 == btInfoReason || 0x2 == btInfoReason) { -+ _rtw_memcpy(btinfo, &pcmd[4], btInfoLen); -+ btinfo[0] = btInfoReason; -+ rtw_btcoex_btinfo_cmd(padapter, btinfo, btInfoLen); -+ } else -+ RTW_INFO("Other BT info reason\n"); -+ } -+ -+ /* send complete event to BT */ -+ { -+ -+ pEvent = (rtw_HCI_event *)(&localBuf[0]); -+ -+ pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; -+ pEvent->Data[0] = 0x1; /* packet # */ -+ pEvent->Data[1] = HCIOPCODELOW(HCI_BT_INFO_NOTIFY, OGF_EXTENSION); -+ pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_INFO_NOTIFY, OGF_EXTENSION); -+ len = len + 3; -+ -+ /* Return parameters starts from here */ -+ pRetPar = &pEvent->Data[len]; -+ pRetPar[0] = status; /* status */ -+ -+ len++; -+ pEvent->Length = len; -+ -+ /* total tx event length + EventCode length + sizeof(length) */ -+ tx_event_length = pEvent->Length + 2; -+#if 0 -+ rtw_btcoex_dump_tx_msg((u8 *)pEvent, tx_event_length, "BT_info_event"); -+#endif -+ status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); -+ -+ return status; -+ /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ -+ } -+} -+ -+u8 rtw_btcoex_parse_BT_patch_ver_info_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) -+{ -+ RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; -+ u16 btPatchVer = 0x0, btHciVer = 0x0; -+ /* u16 *pU2tmp; */ -+ -+ u8 localBuf[6] = ""; -+ u8 *pRetPar; -+ u8 len = 0, tx_event_length = 0; -+ rtw_HCI_event *pEvent; -+ -+ btHciVer = pcmd[0] | pcmd[1] << 8; -+ btPatchVer = pcmd[2] | pcmd[3] << 8; -+ -+ -+ RTW_INFO("%s, cmd:%02x %02x %02x %02x\n", __func__, pcmd[0] , pcmd[1] , pcmd[2] , pcmd[3]); -+ RTW_INFO("%s, HCI Ver:%d, Patch Ver:%d\n", __func__, btHciVer, btPatchVer); -+ -+ rtw_btcoex_SetBtPatchVersion(padapter, btHciVer, btPatchVer); -+ -+ -+ /* send complete event to BT */ -+ { -+ pEvent = (rtw_HCI_event *)(&localBuf[0]); -+ -+ -+ pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; -+ pEvent->Data[0] = 0x1; /* packet # */ -+ pEvent->Data[1] = HCIOPCODELOW(HCI_BT_PATCH_VERSION_NOTIFY, OGF_EXTENSION); -+ pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_PATCH_VERSION_NOTIFY, OGF_EXTENSION); -+ len = len + 3; -+ -+ /* Return parameters starts from here */ -+ pRetPar = &pEvent->Data[len]; -+ pRetPar[0] = status; /* status */ -+ -+ len++; -+ pEvent->Length = len; -+ -+ /* total tx event length + EventCode length + sizeof(length) */ -+ tx_event_length = pEvent->Length + 2; -+#if 0 -+ rtw_btcoex_dump_tx_msg((u8 *)pEvent, tx_event_length, "BT_patch_event"); -+#endif -+ status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); -+ return status; -+ /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ -+ } -+} -+ -+u8 rtw_btcoex_parse_HCI_Ver_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) -+{ -+ RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; -+ u16 hciver = pcmd[0] | pcmd[1] << 8; -+ -+ u8 localBuf[6] = ""; -+ u8 *pRetPar; -+ u8 len = 0, tx_event_length = 0; -+ rtw_HCI_event *pEvent; -+ -+ struct bt_coex_info *pcoex_info = &padapter->coex_info; -+ PBT_MGNT pBtMgnt = &pcoex_info->BtMgnt; -+ pBtMgnt->ExtConfig.HCIExtensionVer = hciver; -+ RTW_INFO("%s, HCI Version: %d\n", __func__, pBtMgnt->ExtConfig.HCIExtensionVer); -+ if (pBtMgnt->ExtConfig.HCIExtensionVer < 4) { -+ status = HCI_STATUS_INVALID_HCI_CMD_PARA_VALUE; -+ RTW_INFO("%s, Version = %d, HCI Version < 4\n", __func__, pBtMgnt->ExtConfig.HCIExtensionVer); -+ } else -+ rtw_btcoex_SetHciVersion(padapter, hciver); -+ /* send complete event to BT */ -+ { -+ pEvent = (rtw_HCI_event *)(&localBuf[0]); -+ -+ -+ pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; -+ pEvent->Data[0] = 0x1; /* packet # */ -+ pEvent->Data[1] = HCIOPCODELOW(HCI_EXTENSION_VERSION_NOTIFY, OGF_EXTENSION); -+ pEvent->Data[2] = HCIOPCODEHIGHT(HCI_EXTENSION_VERSION_NOTIFY, OGF_EXTENSION); -+ len = len + 3; -+ -+ /* Return parameters starts from here */ -+ pRetPar = &pEvent->Data[len]; -+ pRetPar[0] = status; /* status */ -+ -+ len++; -+ pEvent->Length = len; -+ -+ /* total tx event length + EventCode length + sizeof(length) */ -+ tx_event_length = pEvent->Length + 2; -+ -+ status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); -+ return status; -+ /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ -+ } -+ -+} -+ -+u8 rtw_btcoex_parse_WIFI_scan_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) -+{ -+ RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; -+ -+ u8 localBuf[6] = ""; -+ u8 *pRetPar; -+ u8 len = 0, tx_event_length = 0; -+ rtw_HCI_event *pEvent; -+ -+ struct bt_coex_info *pcoex_info = &padapter->coex_info; -+ PBT_MGNT pBtMgnt = &pcoex_info->BtMgnt; -+ pBtMgnt->ExtConfig.bEnableWifiScanNotify = pcmd[0]; -+ RTW_INFO("%s, bEnableWifiScanNotify: %d\n", __func__, pBtMgnt->ExtConfig.bEnableWifiScanNotify); -+ -+ /* send complete event to BT */ -+ { -+ pEvent = (rtw_HCI_event *)(&localBuf[0]); -+ -+ -+ pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; -+ pEvent->Data[0] = 0x1; /* packet # */ -+ pEvent->Data[1] = HCIOPCODELOW(HCI_ENABLE_WIFI_SCAN_NOTIFY, OGF_EXTENSION); -+ pEvent->Data[2] = HCIOPCODEHIGHT(HCI_ENABLE_WIFI_SCAN_NOTIFY, OGF_EXTENSION); -+ len = len + 3; -+ -+ /* Return parameters starts from here */ -+ pRetPar = &pEvent->Data[len]; -+ pRetPar[0] = status; /* status */ -+ -+ len++; -+ pEvent->Length = len; -+ -+ /* total tx event length + EventCode length + sizeof(length) */ -+ tx_event_length = pEvent->Length + 2; -+ -+ status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); -+ return status; -+ /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ -+ } -+} -+ -+u8 rtw_btcoex_parse_HCI_link_status_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) -+{ -+ RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; -+ struct bt_coex_info *pcoex_info = &padapter->coex_info; -+ PBT_MGNT pBtMgnt = &pcoex_info->BtMgnt; -+ /* PBT_DBG pBtDbg=&padapter->MgntInfo.BtInfo.BtDbg; */ -+ u8 i, numOfHandle = 0, numOfAcl = 0; -+ u16 conHandle; -+ u8 btProfile, btCoreSpec, linkRole; -+ u8 *pTriple; -+ -+ u8 localBuf[6] = ""; -+ u8 *pRetPar; -+ u8 len = 0, tx_event_length = 0; -+ rtw_HCI_event *pEvent; -+ -+ /* pBtDbg->dbgHciInfo.hciCmdCntLinkStatusNotify++; */ -+ /* RT_DISP_DATA(FIOCTL, IOCTL_BT_HCICMD_EXT, "LinkStatusNotify, Hex Data :\n", */ -+ /* &pHciCmd->Data[0], pHciCmd->Length); */ -+ -+ RTW_INFO("BTLinkStatusNotify\n"); -+ -+ /* Current only RTL8723 support this command. */ -+ /* pBtMgnt->bSupportProfile = TRUE; */ -+ pBtMgnt->bSupportProfile = _FALSE; -+ -+ pBtMgnt->ExtConfig.NumberOfACL = 0; -+ pBtMgnt->ExtConfig.NumberOfSCO = 0; -+ -+ numOfHandle = pcmd[0]; -+ /* RT_DISP(FIOCTL, IOCTL_BT_HCICMD_EXT, ("numOfHandle = 0x%x\n", numOfHandle)); */ -+ /* RT_DISP(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCIExtensionVer = %d\n", pBtMgnt->ExtConfig.HCIExtensionVer)); */ -+ RTW_INFO("numOfHandle = 0x%x\n", numOfHandle); -+ RTW_INFO("HCIExtensionVer = %d\n", pBtMgnt->ExtConfig.HCIExtensionVer); -+ -+ pTriple = &pcmd[1]; -+ for (i = 0; i < numOfHandle; i++) { -+ if (pBtMgnt->ExtConfig.HCIExtensionVer < 1) { -+ conHandle = *((u8 *)&pTriple[0]); -+ btProfile = pTriple[2]; -+ btCoreSpec = pTriple[3]; -+ if (BT_PROFILE_SCO == btProfile) -+ pBtMgnt->ExtConfig.NumberOfSCO++; -+ else { -+ pBtMgnt->ExtConfig.NumberOfACL++; -+ pBtMgnt->ExtConfig.aclLink[i].ConnectHandle = conHandle; -+ pBtMgnt->ExtConfig.aclLink[i].BTProfile = btProfile; -+ pBtMgnt->ExtConfig.aclLink[i].BTCoreSpec = btCoreSpec; -+ } -+ /* RT_DISP(FIOCTL, IOCTL_BT_HCICMD_EXT, */ -+ /* ("Connection_Handle=0x%x, BTProfile=%d, BTSpec=%d\n", */ -+ /* conHandle, btProfile, btCoreSpec)); */ -+ RTW_INFO("Connection_Handle=0x%x, BTProfile=%d, BTSpec=%d\n", conHandle, btProfile, btCoreSpec); -+ pTriple += 4; -+ } else if (pBtMgnt->ExtConfig.HCIExtensionVer >= 1) { -+ conHandle = *((pu2Byte)&pTriple[0]); -+ btProfile = pTriple[2]; -+ btCoreSpec = pTriple[3]; -+ linkRole = pTriple[4]; -+ if (BT_PROFILE_SCO == btProfile) -+ pBtMgnt->ExtConfig.NumberOfSCO++; -+ else { -+ pBtMgnt->ExtConfig.NumberOfACL++; -+ pBtMgnt->ExtConfig.aclLink[i].ConnectHandle = conHandle; -+ pBtMgnt->ExtConfig.aclLink[i].BTProfile = btProfile; -+ pBtMgnt->ExtConfig.aclLink[i].BTCoreSpec = btCoreSpec; -+ pBtMgnt->ExtConfig.aclLink[i].linkRole = linkRole; -+ } -+ /* RT_DISP(FIOCTL, IOCTL_BT_HCICMD_EXT, */ -+ RTW_INFO("Connection_Handle=0x%x, BTProfile=%d, BTSpec=%d, LinkRole=%d\n", -+ conHandle, btProfile, btCoreSpec, linkRole); -+ pTriple += 5; -+ } -+ } -+ rtw_btcoex_StackUpdateProfileInfo(); -+ -+ /* send complete event to BT */ -+ { -+ pEvent = (rtw_HCI_event *)(&localBuf[0]); -+ -+ -+ pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; -+ pEvent->Data[0] = 0x1; /* packet # */ -+ pEvent->Data[1] = HCIOPCODELOW(HCI_LINK_STATUS_NOTIFY, OGF_EXTENSION); -+ pEvent->Data[2] = HCIOPCODEHIGHT(HCI_LINK_STATUS_NOTIFY, OGF_EXTENSION); -+ len = len + 3; -+ -+ /* Return parameters starts from here */ -+ pRetPar = &pEvent->Data[len]; -+ pRetPar[0] = status; /* status */ -+ -+ len++; -+ pEvent->Length = len; -+ -+ /* total tx event length + EventCode length + sizeof(length) */ -+ tx_event_length = pEvent->Length + 2; -+ -+ status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); -+ return status; -+ /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ -+ } -+ -+ -+} -+ -+u8 rtw_btcoex_parse_HCI_BT_coex_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) -+{ -+ u8 localBuf[6] = ""; -+ u8 *pRetPar; -+ u8 len = 0, tx_event_length = 0; -+ rtw_HCI_event *pEvent; -+ RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; -+ -+ { -+ pEvent = (rtw_HCI_event *)(&localBuf[0]); -+ -+ -+ pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; -+ pEvent->Data[0] = 0x1; /* packet # */ -+ pEvent->Data[1] = HCIOPCODELOW(HCI_BT_COEX_NOTIFY, OGF_EXTENSION); -+ pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_COEX_NOTIFY, OGF_EXTENSION); -+ len = len + 3; -+ -+ /* Return parameters starts from here */ -+ pRetPar = &pEvent->Data[len]; -+ pRetPar[0] = status; /* status */ -+ -+ len++; -+ pEvent->Length = len; -+ -+ /* total tx event length + EventCode length + sizeof(length) */ -+ tx_event_length = pEvent->Length + 2; -+ -+ status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); -+ return status; -+ /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ -+ } -+} -+ -+u8 rtw_btcoex_parse_HCI_BT_operation_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) -+{ -+ u8 localBuf[6] = ""; -+ u8 *pRetPar; -+ u8 len = 0, tx_event_length = 0; -+ rtw_HCI_event *pEvent; -+ RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; -+ -+ RTW_INFO("%s, OP code: %d\n", __func__, pcmd[0]); -+ -+ switch (pcmd[0]) { -+ case HCI_BT_OP_NONE: -+ RTW_INFO("[bt operation] : Operation None!!\n"); -+ break; -+ case HCI_BT_OP_INQUIRY_START: -+ RTW_INFO("[bt operation] : Inquiry start!!\n"); -+ break; -+ case HCI_BT_OP_INQUIRY_FINISH: -+ RTW_INFO("[bt operation] : Inquiry finished!!\n"); -+ break; -+ case HCI_BT_OP_PAGING_START: -+ RTW_INFO("[bt operation] : Paging is started!!\n"); -+ break; -+ case HCI_BT_OP_PAGING_SUCCESS: -+ RTW_INFO("[bt operation] : Paging complete successfully!!\n"); -+ break; -+ case HCI_BT_OP_PAGING_UNSUCCESS: -+ RTW_INFO("[bt operation] : Paging complete unsuccessfully!!\n"); -+ break; -+ case HCI_BT_OP_PAIRING_START: -+ RTW_INFO("[bt operation] : Pairing start!!\n"); -+ break; -+ case HCI_BT_OP_PAIRING_FINISH: -+ RTW_INFO("[bt operation] : Pairing finished!!\n"); -+ break; -+ case HCI_BT_OP_BT_DEV_ENABLE: -+ RTW_INFO("[bt operation] : BT Device is enabled!!\n"); -+ break; -+ case HCI_BT_OP_BT_DEV_DISABLE: -+ RTW_INFO("[bt operation] : BT Device is disabled!!\n"); -+ break; -+ default: -+ RTW_INFO("[bt operation] : Unknown, error!!\n"); -+ break; -+ } -+ -+ /* send complete event to BT */ -+ { -+ pEvent = (rtw_HCI_event *)(&localBuf[0]); -+ -+ -+ pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; -+ pEvent->Data[0] = 0x1; /* packet # */ -+ pEvent->Data[1] = HCIOPCODELOW(HCI_BT_OPERATION_NOTIFY, OGF_EXTENSION); -+ pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_OPERATION_NOTIFY, OGF_EXTENSION); -+ len = len + 3; -+ -+ /* Return parameters starts from here */ -+ pRetPar = &pEvent->Data[len]; -+ pRetPar[0] = status; /* status */ -+ -+ len++; -+ pEvent->Length = len; -+ -+ /* total tx event length + EventCode length + sizeof(length) */ -+ tx_event_length = pEvent->Length + 2; -+ -+ status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); -+ return status; -+ /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ -+ } -+} -+ -+u8 rtw_btcoex_parse_BT_AFH_MAP_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) -+{ -+ u8 localBuf[6] = ""; -+ u8 *pRetPar; -+ u8 len = 0, tx_event_length = 0; -+ rtw_HCI_event *pEvent; -+ RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; -+ -+ { -+ pEvent = (rtw_HCI_event *)(&localBuf[0]); -+ -+ -+ pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; -+ pEvent->Data[0] = 0x1; /* packet # */ -+ pEvent->Data[1] = HCIOPCODELOW(HCI_BT_AFH_MAP_NOTIFY, OGF_EXTENSION); -+ pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_AFH_MAP_NOTIFY, OGF_EXTENSION); -+ len = len + 3; -+ -+ /* Return parameters starts from here */ -+ pRetPar = &pEvent->Data[len]; -+ pRetPar[0] = status; /* status */ -+ -+ len++; -+ pEvent->Length = len; -+ -+ /* total tx event length + EventCode length + sizeof(length) */ -+ tx_event_length = pEvent->Length + 2; -+ -+ status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); -+ return status; -+ /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ -+ } -+} -+ -+u8 rtw_btcoex_parse_BT_register_val_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) -+{ -+ -+ u8 localBuf[6] = ""; -+ u8 *pRetPar; -+ u8 len = 0, tx_event_length = 0; -+ rtw_HCI_event *pEvent; -+ RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; -+ -+ { -+ pEvent = (rtw_HCI_event *)(&localBuf[0]); -+ -+ -+ pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; -+ pEvent->Data[0] = 0x1; /* packet # */ -+ pEvent->Data[1] = HCIOPCODELOW(HCI_BT_REGISTER_VALUE_NOTIFY, OGF_EXTENSION); -+ pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_REGISTER_VALUE_NOTIFY, OGF_EXTENSION); -+ len = len + 3; -+ -+ /* Return parameters starts from here */ -+ pRetPar = &pEvent->Data[len]; -+ pRetPar[0] = status; /* status */ -+ -+ len++; -+ pEvent->Length = len; -+ -+ /* total tx event length + EventCode length + sizeof(length) */ -+ tx_event_length = pEvent->Length + 2; -+ -+ status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); -+ return status; -+ /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ -+ } -+} -+ -+u8 rtw_btcoex_parse_HCI_BT_abnormal_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) -+{ -+ u8 localBuf[6] = ""; -+ u8 *pRetPar; -+ u8 len = 0, tx_event_length = 0; -+ rtw_HCI_event *pEvent; -+ RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; -+ -+ { -+ pEvent = (rtw_HCI_event *)(&localBuf[0]); -+ -+ -+ pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; -+ pEvent->Data[0] = 0x1; /* packet # */ -+ pEvent->Data[1] = HCIOPCODELOW(HCI_BT_ABNORMAL_NOTIFY, OGF_EXTENSION); -+ pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_ABNORMAL_NOTIFY, OGF_EXTENSION); -+ len = len + 3; -+ -+ /* Return parameters starts from here */ -+ pRetPar = &pEvent->Data[len]; -+ pRetPar[0] = status; /* status */ -+ -+ len++; -+ pEvent->Length = len; -+ -+ /* total tx event length + EventCode length + sizeof(length) */ -+ tx_event_length = pEvent->Length + 2; -+ -+ status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); -+ return status; -+ /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ -+ } -+} -+ -+u8 rtw_btcoex_parse_HCI_query_RF_status_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) -+{ -+ u8 localBuf[6] = ""; -+ u8 *pRetPar; -+ u8 len = 0, tx_event_length = 0; -+ rtw_HCI_event *pEvent; -+ RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; -+ -+ { -+ pEvent = (rtw_HCI_event *)(&localBuf[0]); -+ -+ -+ pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; -+ pEvent->Data[0] = 0x1; /* packet # */ -+ pEvent->Data[1] = HCIOPCODELOW(HCI_QUERY_RF_STATUS, OGF_EXTENSION); -+ pEvent->Data[2] = HCIOPCODEHIGHT(HCI_QUERY_RF_STATUS, OGF_EXTENSION); -+ len = len + 3; -+ -+ /* Return parameters starts from here */ -+ pRetPar = &pEvent->Data[len]; -+ pRetPar[0] = status; /* status */ -+ -+ len++; -+ pEvent->Length = len; -+ -+ /* total tx event length + EventCode length + sizeof(length) */ -+ tx_event_length = pEvent->Length + 2; -+ -+ status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); -+ return status; -+ /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ -+ } -+} -+ -+/***************************************** -+* HCI cmd format : -+*| 15 - 0 | -+*| OPcode (OCF|OGF<<10) | -+*| 15 - 8 |7 - 0 | -+*|Cmd para |Cmd para Length | -+*|Cmd para...... | -+******************************************/ -+ -+/* bit 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 -+ * | OCF | OGF | */ -+void rtw_btcoex_parse_hci_extend_cmd(_adapter *padapter, u8 *pcmd, u16 len, const u16 hci_OCF) -+{ -+ -+ RTW_INFO("%s: OCF: %x\n", __func__, hci_OCF); -+ switch (hci_OCF) { -+ case HCI_EXTENSION_VERSION_NOTIFY: -+ RTW_INFO("HCI_EXTENSION_VERSION_NOTIFY\n"); -+ rtw_btcoex_parse_HCI_Ver_notify_cmd(padapter, pcmd, len); -+ break; -+ case HCI_LINK_STATUS_NOTIFY: -+ RTW_INFO("HCI_LINK_STATUS_NOTIFY\n"); -+ rtw_btcoex_parse_HCI_link_status_notify_cmd(padapter, pcmd, len); -+ break; -+ case HCI_BT_OPERATION_NOTIFY: -+ /* only for 8723a 2ant */ -+ RTW_INFO("HCI_BT_OPERATION_NOTIFY\n"); -+ rtw_btcoex_parse_HCI_BT_operation_notify_cmd(padapter, pcmd, len); -+ /* */ -+ break; -+ case HCI_ENABLE_WIFI_SCAN_NOTIFY: -+ RTW_INFO("HCI_ENABLE_WIFI_SCAN_NOTIFY\n"); -+ rtw_btcoex_parse_WIFI_scan_notify_cmd(padapter, pcmd, len); -+ break; -+ case HCI_QUERY_RF_STATUS: -+ /* only for 8723b 2ant */ -+ RTW_INFO("HCI_QUERY_RF_STATUS\n"); -+ rtw_btcoex_parse_HCI_query_RF_status_cmd(padapter, pcmd, len); -+ break; -+ case HCI_BT_ABNORMAL_NOTIFY: -+ RTW_INFO("HCI_BT_ABNORMAL_NOTIFY\n"); -+ rtw_btcoex_parse_HCI_BT_abnormal_notify_cmd(padapter, pcmd, len); -+ break; -+ case HCI_BT_INFO_NOTIFY: -+ RTW_INFO("HCI_BT_INFO_NOTIFY\n"); -+ rtw_btcoex_parse_BT_info_notify_cmd(padapter, pcmd, len); -+ break; -+ case HCI_BT_COEX_NOTIFY: -+ RTW_INFO("HCI_BT_COEX_NOTIFY\n"); -+ rtw_btcoex_parse_HCI_BT_coex_notify_cmd(padapter, pcmd, len); -+ break; -+ case HCI_BT_PATCH_VERSION_NOTIFY: -+ RTW_INFO("HCI_BT_PATCH_VERSION_NOTIFY\n"); -+ rtw_btcoex_parse_BT_patch_ver_info_cmd(padapter, pcmd, len); -+ break; -+ case HCI_BT_AFH_MAP_NOTIFY: -+ RTW_INFO("HCI_BT_AFH_MAP_NOTIFY\n"); -+ rtw_btcoex_parse_BT_AFH_MAP_notify_cmd(padapter, pcmd, len); -+ break; -+ case HCI_BT_REGISTER_VALUE_NOTIFY: -+ RTW_INFO("HCI_BT_REGISTER_VALUE_NOTIFY\n"); -+ rtw_btcoex_parse_BT_register_val_notify_cmd(padapter, pcmd, len); -+ break; -+ default: -+ RTW_INFO("ERROR!!! Unknown OCF: %x\n", hci_OCF); -+ break; -+ -+ } -+} -+ -+void rtw_btcoex_parse_hci_cmd(_adapter *padapter, u8 *pcmd, u16 len) -+{ -+ u16 opcode = pcmd[0] | pcmd[1] << 8; -+ u16 hci_OGF = HCI_OGF(opcode); -+ u16 hci_OCF = HCI_OCF(opcode); -+ u8 cmdlen = len - 3; -+ u8 pare_len = pcmd[2]; -+ -+ RTW_INFO("%s OGF: %x,OCF: %x\n", __func__, hci_OGF, hci_OCF); -+ switch (hci_OGF) { -+ case OGF_EXTENSION: -+ RTW_INFO("HCI_EXTENSION_CMD_OGF\n"); -+ rtw_btcoex_parse_hci_extend_cmd(padapter, &pcmd[3], cmdlen, hci_OCF); -+ break; -+ default: -+ RTW_INFO("Other OGF: %x\n", hci_OGF); -+ break; -+ } -+} -+ -+u16 rtw_btcoex_parse_recv_data(u8 *msg, u8 msg_size) -+{ -+ u8 cmp_msg1[32] = attend_ack; -+ u8 cmp_msg2[32] = leave_ack; -+ u8 cmp_msg3[32] = bt_leave; -+ u8 cmp_msg4[32] = invite_req; -+ u8 cmp_msg5[32] = attend_req; -+ u8 cmp_msg6[32] = invite_rsp; -+ u8 res = OTHER; -+ -+ if (_rtw_memcmp(cmp_msg1, msg, msg_size) == _TRUE) { -+ /*RTW_INFO("%s, msg:%s\n",__func__,msg);*/ -+ res = RX_ATTEND_ACK; -+ } else if (_rtw_memcmp(cmp_msg2, msg, msg_size) == _TRUE) { -+ /*RTW_INFO("%s, msg:%s\n",__func__,msg);*/ -+ res = RX_LEAVE_ACK; -+ } else if (_rtw_memcmp(cmp_msg3, msg, msg_size) == _TRUE) { -+ /*RTW_INFO("%s, msg:%s\n",__func__,msg);*/ -+ res = RX_BT_LEAVE; -+ } else if (_rtw_memcmp(cmp_msg4, msg, msg_size) == _TRUE) { -+ /*RTW_INFO("%s, msg:%s\n",__func__,msg);*/ -+ res = RX_INVITE_REQ; -+ } else if (_rtw_memcmp(cmp_msg5, msg, msg_size) == _TRUE) -+ res = RX_ATTEND_REQ; -+ else if (_rtw_memcmp(cmp_msg6, msg, msg_size) == _TRUE) -+ res = RX_INVITE_RSP; -+ else { -+ /*RTW_INFO("%s, %s\n", __func__, msg);*/ -+ res = OTHER; -+ } -+ -+ /*RTW_INFO("%s, res:%d\n", __func__, res);*/ -+ -+ return res; -+} -+ -+void rtw_btcoex_recvmsgbysocket(void *data) -+{ -+ u8 recv_data[255]; -+ u8 tx_msg[255] = leave_ack; -+ u32 len = 0; -+ u16 recv_length = 0; -+ u16 parse_res = 0; -+#if 0 -+ u8 para_len = 0, polling_enable = 0, poling_interval = 0, reason = 0, btinfo_len = 0; -+ u8 btinfo[BT_INFO_LEN] = {0}; -+#endif -+ -+ struct bt_coex_info *pcoex_info = NULL; -+ struct sock *sk = NULL; -+ struct sk_buff *skb = NULL; -+ -+ /*RTW_INFO("%s\n",__func__);*/ -+ -+ if (pbtcoexadapter == NULL) { -+ RTW_INFO("%s: btcoexadapter NULL!\n", __func__); -+ return; -+ } -+ -+ pcoex_info = &pbtcoexadapter->coex_info; -+ sk = pcoex_info->sk_store; -+ -+ if (sk == NULL) { -+ RTW_INFO("%s: critical error when receive socket data!\n", __func__); -+ return; -+ } -+ -+ len = skb_queue_len(&sk->sk_receive_queue); -+ while (len > 0) { -+ skb = skb_dequeue(&sk->sk_receive_queue); -+ -+ /*important: cut the udp header from skb->data! header length is 8 byte*/ -+ recv_length = skb->len - 8; -+ _rtw_memset(recv_data, 0, sizeof(recv_data)); -+ _rtw_memcpy(recv_data, skb->data + 8, recv_length); -+ -+ parse_res = rtw_btcoex_parse_recv_data(recv_data, recv_length); -+#if 0 -+ if (RX_ATTEND_ACK == parse_res) { -+ /* attend ack */ -+ pcoex_info->BT_attend = _TRUE; -+ RTW_INFO("RX_ATTEND_ACK!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); -+ } else if (RX_ATTEND_REQ == parse_res) { -+ /* attend req from BT */ -+ pcoex_info->BT_attend = _TRUE; -+ RTW_INFO("RX_BT_ATTEND_REQ!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); -+ rtw_btcoex_sendmsgbysocket(pbtcoexadapter, attend_ack, sizeof(attend_ack), _FALSE); -+ } else if (RX_INVITE_REQ == parse_res) { -+ /* invite req from BT */ -+ pcoex_info->BT_attend = _TRUE; -+ RTW_INFO("RX_INVITE_REQ!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); -+ rtw_btcoex_sendmsgbysocket(pbtcoexadapter, invite_rsp, sizeof(invite_rsp), _FALSE); -+ } else if (RX_INVITE_RSP == parse_res) { -+ /* invite rsp */ -+ pcoex_info->BT_attend = _TRUE; -+ RTW_INFO("RX_INVITE_RSP!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); -+ } else if (RX_LEAVE_ACK == parse_res) { -+ /* mean BT know wifi will leave */ -+ pcoex_info->BT_attend = _FALSE; -+ RTW_INFO("RX_LEAVE_ACK!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); -+ } else if (RX_BT_LEAVE == parse_res) { -+ /* BT leave */ -+ rtw_btcoex_sendmsgbysocket(pbtcoexadapter, leave_ack, sizeof(leave_ack), _FALSE); /* no ack */ -+ pcoex_info->BT_attend = _FALSE; -+ RTW_INFO("RX_BT_LEAVE!sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); -+ } else { -+ /* todo: check if recv data are really hci cmds */ -+ if (_TRUE == pcoex_info->BT_attend) -+ rtw_btcoex_parse_hci_cmd(pbtcoexadapter, recv_data, recv_length); -+ } -+#endif -+ switch (parse_res) { -+ case RX_ATTEND_ACK: -+ /* attend ack */ -+ pcoex_info->BT_attend = _TRUE; -+ RTW_INFO("RX_ATTEND_ACK!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); -+ rtw_btcoex_pta_off_on_notify(pbtcoexadapter, pcoex_info->BT_attend); -+ break; -+ -+ case RX_ATTEND_REQ: -+ pcoex_info->BT_attend = _TRUE; -+ RTW_INFO("RX_BT_ATTEND_REQ!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); -+ rtw_btcoex_sendmsgbysocket(pbtcoexadapter, attend_ack, sizeof(attend_ack), _FALSE); -+ rtw_btcoex_pta_off_on_notify(pbtcoexadapter, pcoex_info->BT_attend); -+ break; -+ -+ case RX_INVITE_REQ: -+ /* invite req from BT */ -+ pcoex_info->BT_attend = _TRUE; -+ RTW_INFO("RX_INVITE_REQ!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); -+ rtw_btcoex_sendmsgbysocket(pbtcoexadapter, invite_rsp, sizeof(invite_rsp), _FALSE); -+ rtw_btcoex_pta_off_on_notify(pbtcoexadapter, pcoex_info->BT_attend); -+ break; -+ -+ case RX_INVITE_RSP: -+ /*invite rsp*/ -+ pcoex_info->BT_attend = _TRUE; -+ RTW_INFO("RX_INVITE_RSP!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); -+ rtw_btcoex_pta_off_on_notify(pbtcoexadapter, pcoex_info->BT_attend); -+ break; -+ -+ case RX_LEAVE_ACK: -+ /* mean BT know wifi will leave */ -+ pcoex_info->BT_attend = _FALSE; -+ RTW_INFO("RX_LEAVE_ACK!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); -+ rtw_btcoex_pta_off_on_notify(pbtcoexadapter, pcoex_info->BT_attend); -+ break; -+ -+ case RX_BT_LEAVE: -+ /* BT leave */ -+ rtw_btcoex_sendmsgbysocket(pbtcoexadapter, leave_ack, sizeof(leave_ack), _FALSE); /* no ack */ -+ pcoex_info->BT_attend = _FALSE; -+ RTW_INFO("RX_BT_LEAVE!sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); -+ rtw_btcoex_pta_off_on_notify(pbtcoexadapter, pcoex_info->BT_attend); -+ break; -+ -+ default: -+ if (_TRUE == pcoex_info->BT_attend) -+ rtw_btcoex_parse_hci_cmd(pbtcoexadapter, recv_data, recv_length); -+ else -+ RTW_INFO("ERROR!! BT is UP\n"); -+ break; -+ -+ } -+ -+ len--; -+ kfree_skb(skb); -+ } -+} -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0)) -+ void rtw_btcoex_recvmsg_init(struct sock *sk_in, s32 bytes) -+#else -+ void rtw_btcoex_recvmsg_init(struct sock *sk_in) -+#endif -+{ -+ struct bt_coex_info *pcoex_info = NULL; -+ -+ if (pbtcoexadapter == NULL) { -+ RTW_INFO("%s: btcoexadapter NULL\n", __func__); -+ return; -+ } -+ pcoex_info = &pbtcoexadapter->coex_info; -+ pcoex_info->sk_store = sk_in; -+ if (pcoex_info->btcoex_wq != NULL) -+ queue_delayed_work(pcoex_info->btcoex_wq, &pcoex_info->recvmsg_work, 0); -+ else -+ RTW_INFO("%s: BTCOEX workqueue NULL\n", __func__); -+} -+ -+u8 rtw_btcoex_sendmsgbysocket(_adapter *padapter, u8 *msg, u8 msg_size, bool force) -+{ -+ u8 error; -+ struct msghdr udpmsg; -+ mm_segment_t oldfs; -+ struct iovec iov; -+ struct bt_coex_info *pcoex_info = &padapter->coex_info; -+ -+ /* RTW_INFO("%s: msg:%s, force:%s\n", __func__, msg, force == _TRUE?"TRUE":"FALSE"); */ -+ if (_FALSE == force) { -+ if (_FALSE == pcoex_info->BT_attend) { -+ RTW_INFO("TX Blocked: WiFi-BT disconnected\n"); -+ return _FAIL; -+ } -+ } -+ -+ iov.iov_base = (void *)msg; -+ iov.iov_len = msg_size; -+ udpmsg.msg_name = &pcoex_info->bt_sockaddr; -+ udpmsg.msg_namelen = sizeof(struct sockaddr_in); -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) -+ /* referece:sock_xmit in kernel code -+ * WRITE for sock_sendmsg, READ for sock_recvmsg -+ * third parameter for msg_iovlen -+ * last parameter for iov_len -+ */ -+ iov_iter_init(&udpmsg.msg_iter, WRITE, &iov, 1, msg_size); -+#else -+ udpmsg.msg_iov = &iov; -+ udpmsg.msg_iovlen = 1; -+#endif -+ udpmsg.msg_control = NULL; -+ udpmsg.msg_controllen = 0; -+ udpmsg.msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL; -+ oldfs = get_fs(); -+ set_fs(KERNEL_DS); -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) -+ error = sock_sendmsg(pcoex_info->udpsock, &udpmsg); -+#else -+ error = sock_sendmsg(pcoex_info->udpsock, &udpmsg, msg_size); -+#endif -+ set_fs(oldfs); -+ if (error < 0) { -+ RTW_INFO("Error when sendimg msg, error:%d\n", error); -+ return _FAIL; -+ } else -+ return _SUCCESS; -+} -+ -+u8 rtw_btcoex_create_kernel_socket(_adapter *padapter) -+{ -+ s8 kernel_socket_err; -+ u8 tx_msg[255] = attend_req; -+ struct bt_coex_info *pcoex_info = &padapter->coex_info; -+ s32 sock_reuse = 1; -+ u8 status = _FAIL; -+ -+ RTW_INFO("%s CONNECT_PORT %d\n", __func__, CONNECT_PORT); -+ -+ if (NULL == pcoex_info) { -+ RTW_INFO("coex_info: NULL\n"); -+ status = _FAIL; -+ } -+ -+ kernel_socket_err = sock_create(PF_INET, SOCK_DGRAM, 0, &pcoex_info->udpsock); -+ -+ if (kernel_socket_err < 0) { -+ RTW_INFO("Error during creation of socket error:%d\n", kernel_socket_err); -+ status = _FAIL; -+ } else { -+ _rtw_memset(&(pcoex_info->wifi_sockaddr), 0, sizeof(pcoex_info->wifi_sockaddr)); -+ pcoex_info->wifi_sockaddr.sin_family = AF_INET; -+ pcoex_info->wifi_sockaddr.sin_port = htons(CONNECT_PORT); -+ pcoex_info->wifi_sockaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); -+ -+ _rtw_memset(&(pcoex_info->bt_sockaddr), 0, sizeof(pcoex_info->bt_sockaddr)); -+ pcoex_info->bt_sockaddr.sin_family = AF_INET; -+ pcoex_info->bt_sockaddr.sin_port = htons(CONNECT_PORT_BT); -+ pcoex_info->bt_sockaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); -+ -+ pcoex_info->sk_store = NULL; -+ kernel_socket_err = pcoex_info->udpsock->ops->bind(pcoex_info->udpsock, (struct sockaddr *)&pcoex_info->wifi_sockaddr, -+ sizeof(pcoex_info->wifi_sockaddr)); -+ if (kernel_socket_err == 0) { -+ RTW_INFO("binding socket success\n"); -+ pcoex_info->udpsock->sk->sk_data_ready = rtw_btcoex_recvmsg_init; -+ pcoex_info->sock_open |= KERNEL_SOCKET_OK; -+ pcoex_info->BT_attend = _FALSE; -+ RTW_INFO("WIFI sending attend_req\n"); -+ rtw_btcoex_sendmsgbysocket(padapter, attend_req, sizeof(attend_req), _TRUE); -+ status = _SUCCESS; -+ } else { -+ pcoex_info->BT_attend = _FALSE; -+ sock_release(pcoex_info->udpsock); /* bind fail release socket */ -+ RTW_INFO("Error binding socket: %d\n", kernel_socket_err); -+ status = _FAIL; -+ } -+ -+ } -+ -+ return status; -+} -+ -+void rtw_btcoex_close_kernel_socket(_adapter *padapter) -+{ -+ struct bt_coex_info *pcoex_info = &padapter->coex_info; -+ if (pcoex_info->sock_open & KERNEL_SOCKET_OK) { -+ RTW_INFO("release kernel socket\n"); -+ sock_release(pcoex_info->udpsock); -+ pcoex_info->sock_open &= ~(KERNEL_SOCKET_OK); -+ if (_TRUE == pcoex_info->BT_attend) -+ pcoex_info->BT_attend = _FALSE; -+ -+ RTW_INFO("sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); -+ } -+} -+ -+void rtw_btcoex_init_socket(_adapter *padapter) -+{ -+ -+ u8 is_invite = _FALSE; -+ struct bt_coex_info *pcoex_info = &padapter->coex_info; -+ RTW_INFO("%s\n", __func__); -+ if (_FALSE == pcoex_info->is_exist) { -+ _rtw_memset(pcoex_info, 0, sizeof(struct bt_coex_info)); -+ pcoex_info->btcoex_wq = create_workqueue("BTCOEX"); -+ INIT_DELAYED_WORK(&pcoex_info->recvmsg_work, -+ (void *)rtw_btcoex_recvmsgbysocket); -+ pbtcoexadapter = padapter; -+ /* We expect BT is off if BT don't send ack to wifi */ -+ RTW_INFO("We expect BT is off if BT send ack to wifi\n"); -+ rtw_btcoex_pta_off_on_notify(pbtcoexadapter, _FALSE); -+ if (rtw_btcoex_create_kernel_socket(padapter) == _SUCCESS) -+ pcoex_info->is_exist = _TRUE; -+ else { -+ pcoex_info->is_exist = _FALSE; -+ pbtcoexadapter = NULL; -+ } -+ -+ RTW_INFO("%s: pbtcoexadapter:%p, coex_info->is_exist: %s\n" -+ , __func__, pbtcoexadapter, pcoex_info->is_exist == _TRUE ? "TRUE" : "FALSE"); -+ } -+} -+ -+void rtw_btcoex_close_socket(_adapter *padapter) -+{ -+ struct bt_coex_info *pcoex_info = &padapter->coex_info; -+ -+ RTW_INFO("%s--coex_info->is_exist: %s, pcoex_info->BT_attend:%s\n" -+ , __func__, pcoex_info->is_exist == _TRUE ? "TRUE" : "FALSE", pcoex_info->BT_attend == _TRUE ? "TRUE" : "FALSE"); -+ -+ if (_TRUE == pcoex_info->is_exist) { -+ if (_TRUE == pcoex_info->BT_attend) { -+ /*inform BT wifi leave*/ -+ rtw_btcoex_sendmsgbysocket(padapter, wifi_leave, sizeof(wifi_leave), _FALSE); -+ msleep(50); -+ } -+ -+ if (pcoex_info->btcoex_wq != NULL) { -+ flush_workqueue(pcoex_info->btcoex_wq); -+ destroy_workqueue(pcoex_info->btcoex_wq); -+ } -+ -+ rtw_btcoex_close_kernel_socket(padapter); -+ pbtcoexadapter = NULL; -+ pcoex_info->is_exist = _FALSE; -+ } -+} -+ -+void rtw_btcoex_dump_tx_msg(u8 *tx_msg, u8 len, u8 *msg_name) -+{ -+ u8 i = 0; -+ RTW_INFO("======> Msg name: %s\n", msg_name); -+ for (i = 0; i < len; i++) -+ printk("%02x ", tx_msg[i]); -+ printk("\n"); -+ RTW_INFO("Msg name: %s <======\n", msg_name); -+} -+ -+/* Porting from Windows team */ -+void rtw_btcoex_SendEventExtBtCoexControl(PADAPTER padapter, u8 bNeedDbgRsp, u8 dataLen, void *pData) -+{ -+ u8 len = 0, tx_event_length = 0; -+ u8 localBuf[32] = ""; -+ u8 *pRetPar; -+ u8 opCode = 0; -+ u8 *pInBuf = (pu1Byte)pData; -+ u8 *pOpCodeContent; -+ rtw_HCI_event *pEvent; -+ -+ opCode = pInBuf[0]; -+ -+ RTW_INFO("%s, OPCode:%02x\n", __func__, opCode); -+ -+ pEvent = (rtw_HCI_event *)(&localBuf[0]); -+ -+ /* len += bthci_ExtensionEventHeaderRtk(&localBuf[0], */ -+ /* HCI_EVENT_EXT_BT_COEX_CONTROL); */ -+ pEvent->EventCode = HCI_EVENT_EXTENSION_RTK; -+ pEvent->Data[0] = HCI_EVENT_EXT_BT_COEX_CONTROL; /* extension event code */ -+ len++; -+ -+ /* Return parameters starts from here */ -+ pRetPar = &pEvent->Data[len]; -+ _rtw_memcpy(&pRetPar[0], pData, dataLen); -+ -+ len += dataLen; -+ -+ pEvent->Length = len; -+ -+ /* total tx event length + EventCode length + sizeof(length) */ -+ tx_event_length = pEvent->Length + 2; -+#if 0 -+ rtw_btcoex_dump_tx_msg((u8 *)pEvent, tx_event_length, "BT COEX CONTROL", _FALSE); -+#endif -+ rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); -+ -+} -+ -+/* Porting from Windows team */ -+void rtw_btcoex_SendEventExtBtInfoControl(PADAPTER padapter, u8 dataLen, void *pData) -+{ -+ rtw_HCI_event *pEvent; -+ u8 *pRetPar; -+ u8 len = 0, tx_event_length = 0; -+ u8 localBuf[32] = ""; -+ -+ struct bt_coex_info *pcoex_info = &padapter->coex_info; -+ PBT_MGNT pBtMgnt = &pcoex_info->BtMgnt; -+ -+ /* RTW_INFO("%s\n",__func__);*/ -+ if (pBtMgnt->ExtConfig.HCIExtensionVer < 4) { /* not support */ -+ RTW_INFO("ERROR: HCIExtensionVer = %d, HCIExtensionVer<4 !!!!\n", pBtMgnt->ExtConfig.HCIExtensionVer); -+ return; -+ } -+ -+ pEvent = (rtw_HCI_event *)(&localBuf[0]); -+ -+ /* len += bthci_ExtensionEventHeaderRtk(&localBuf[0], */ -+ /* HCI_EVENT_EXT_BT_INFO_CONTROL); */ -+ pEvent->EventCode = HCI_EVENT_EXTENSION_RTK; -+ pEvent->Data[0] = HCI_EVENT_EXT_BT_INFO_CONTROL; /* extension event code */ -+ len++; -+ -+ /* Return parameters starts from here */ -+ pRetPar = &pEvent->Data[len]; -+ _rtw_memcpy(&pRetPar[0], pData, dataLen); -+ -+ len += dataLen; -+ -+ pEvent->Length = len; -+ -+ /* total tx event length + EventCode length + sizeof(length) */ -+ tx_event_length = pEvent->Length + 2; -+#if 0 -+ rtw_btcoex_dump_tx_msg((u8 *)pEvent, tx_event_length, "BT INFO CONTROL"); -+#endif -+ rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); -+ -+} -+ -+void rtw_btcoex_SendScanNotify(PADAPTER padapter, u8 scanType) -+{ -+ u8 len = 0, tx_event_length = 0; -+ u8 localBuf[7] = ""; -+ u8 *pRetPar; -+ u8 *pu1Temp; -+ rtw_HCI_event *pEvent; -+ struct bt_coex_info *pcoex_info = &padapter->coex_info; -+ PBT_MGNT pBtMgnt = &pcoex_info->BtMgnt; -+ -+ /* if(!pBtMgnt->BtOperationOn) -+ * return; */ -+ -+ pEvent = (rtw_HCI_event *)(&localBuf[0]); -+ -+ /* len += bthci_ExtensionEventHeaderRtk(&localBuf[0], -+ * HCI_EVENT_EXT_WIFI_SCAN_NOTIFY); */ -+ -+ pEvent->EventCode = HCI_EVENT_EXTENSION_RTK; -+ pEvent->Data[0] = HCI_EVENT_EXT_WIFI_SCAN_NOTIFY; /* extension event code */ -+ len++; -+ -+ /* Return parameters starts from here */ -+ /* pRetPar = &PPacketIrpEvent->Data[len]; */ -+ /* pu1Temp = (u8 *)&pRetPar[0]; */ -+ /* *pu1Temp = scanType; */ -+ pEvent->Data[len] = scanType; -+ len += 1; -+ -+ pEvent->Length = len; -+ -+ /* total tx event length + EventCode length + sizeof(length) */ -+ tx_event_length = pEvent->Length + 2; -+#if 0 -+ rtw_btcoex_dump_tx_msg((u8 *)pEvent, tx_event_length, "WIFI SCAN OPERATION"); -+#endif -+ rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); -+} -+#endif /* CONFIG_BT_COEXIST_SOCKET_TRX */ -+#endif /* CONFIG_BT_COEXIST */ -+ -+void rtw_btcoex_set_ant_info(PADAPTER padapter) -+{ -+#ifdef CONFIG_BT_COEXIST -+ PHAL_DATA_TYPE hal = GET_HAL_DATA(padapter); -+ -+ if (hal->EEPROMBluetoothCoexist == _TRUE) { -+ u8 bMacPwrCtrlOn = _FALSE; -+ -+ rtw_btcoex_AntInfoSetting(padapter); -+ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); -+ if (bMacPwrCtrlOn == _TRUE) -+ rtw_btcoex_PowerOnSetting(padapter); -+ } -+ else -+#endif -+ rtw_btcoex_wifionly_AntInfoSetting(padapter); -+} -+ -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_btcoex_wifionly.c linux-5.8/3rdparty/rtl8812au/core/rtw_btcoex_wifionly.c -new file mode 100644 -index 000000000..d9872b022 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_btcoex_wifionly.c -@@ -0,0 +1,47 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2013 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+#include -+#include -+#include -+ -+void rtw_btcoex_wifionly_switchband_notify(PADAPTER padapter) -+{ -+ hal_btcoex_wifionly_switchband_notify(padapter); -+} -+ -+void rtw_btcoex_wifionly_scan_notify(PADAPTER padapter) -+{ -+ hal_btcoex_wifionly_scan_notify(padapter); -+} -+ -+void rtw_btcoex_wifionly_connect_notify(PADAPTER padapter) -+{ -+ hal_btcoex_wifionly_connect_notify(padapter); -+} -+ -+void rtw_btcoex_wifionly_hw_config(PADAPTER padapter) -+{ -+ hal_btcoex_wifionly_hw_config(padapter); -+} -+ -+void rtw_btcoex_wifionly_initialize(PADAPTER padapter) -+{ -+ hal_btcoex_wifionly_initlizevariables(padapter); -+} -+ -+void rtw_btcoex_wifionly_AntInfoSetting(PADAPTER padapter) -+{ -+ hal_btcoex_wifionly_AntInfoSetting(padapter); -+} -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_chplan.c linux-5.8/3rdparty/rtl8812au/core/rtw_chplan.c -new file mode 100644 -index 000000000..34263a5fd ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_chplan.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_chplan.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_chplan.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_chplan.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_chplan.c 2021-03-07 18:16:17.018954351 +0200 @@ -0,0 +1,1193 @@ +/****************************************************************************** + * @@ -28835,11 +25910,9 @@ index 000000000..34263a5fd +{ + RTW_PRINT_SEL(sel, "%s-%s\n", RTW_DOMAIN_MAP_VER, RTW_COUNTRY_MAP_VER); +} -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_chplan.h linux-5.8/3rdparty/rtl8812au/core/rtw_chplan.h -new file mode 100644 -index 000000000..cdf9f75b2 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_chplan.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_chplan.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_chplan.h +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_chplan.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_chplan.h 2021-03-07 18:16:17.018954351 +0200 @@ -0,0 +1,181 @@ +/****************************************************************************** + * @@ -29022,11 +26095,9 @@ index 000000000..cdf9f75b2 +void dump_chplan_ver(void *sel); + +#endif /* __RTW_CHPLAN_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_cmd.c linux-5.8/3rdparty/rtl8812au/core/rtw_cmd.c -new file mode 100644 -index 000000000..2984f9bea ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_cmd.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_cmd.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_cmd.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_cmd.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_cmd.c 2021-03-07 18:16:17.018954351 +0200 @@ -0,0 +1,5765 @@ +/****************************************************************************** + * @@ -34793,11 +31864,9 @@ index 000000000..2984f9bea + + +} -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_debug.c linux-5.8/3rdparty/rtl8812au/core/rtw_debug.c -new file mode 100644 -index 000000000..22ff44f8b ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_debug.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_debug.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_debug.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_debug.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_debug.c 2021-03-07 18:16:17.019954399 +0200 @@ -0,0 +1,7096 @@ +/****************************************************************************** + * @@ -41895,11 +38964,9 @@ index 000000000..22ff44f8b + return count; +} +#endif /* CONFIG_RTW_SW_LED */ -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_eeprom.c linux-5.8/3rdparty/rtl8812au/core/rtw_eeprom.c -new file mode 100644 -index 000000000..d48996e86 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_eeprom.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_eeprom.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_eeprom.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_eeprom.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_eeprom.c 2021-03-07 18:16:17.019954399 +0200 @@ -0,0 +1,369 @@ +/****************************************************************************** + * @@ -42270,11 +39337,9 @@ index 000000000..d48996e86 + + +} -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_ieee80211.c linux-5.8/3rdparty/rtl8812au/core/rtw_ieee80211.c -new file mode 100644 -index 000000000..94e3d5985 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_ieee80211.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_ieee80211.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_ieee80211.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_ieee80211.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_ieee80211.c 2021-03-07 18:16:17.019954399 +0200 @@ -0,0 +1,2934 @@ +/****************************************************************************** + * @@ -45210,11 +42275,9 @@ index 000000000..94e3d5985 + return _action_public_str[action]; +} + -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_io.c linux-5.8/3rdparty/rtl8812au/core/rtw_io.c -new file mode 100644 -index 000000000..5751c071a ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_io.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_io.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_io.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_io.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_io.c 2021-03-07 18:16:17.019954399 +0200 @@ -0,0 +1,899 @@ +/****************************************************************************** + * @@ -46115,11 +43178,9 @@ index 000000000..5751c071a +#endif /* CONFIG_SDIO_HCI */ + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_ioctl_query.c linux-5.8/3rdparty/rtl8812au/core/rtw_ioctl_query.c -new file mode 100644 -index 000000000..6f7613ecd ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_ioctl_query.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_ioctl_query.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_ioctl_query.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_ioctl_query.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_ioctl_query.c 2021-03-07 18:16:17.019954399 +0200 @@ -0,0 +1,166 @@ +/****************************************************************************** + * @@ -46287,11 +43348,9 @@ index 000000000..6f7613ecd + return _TRUE; +} +#endif -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_ioctl_rtl.c linux-5.8/3rdparty/rtl8812au/core/rtw_ioctl_rtl.c -new file mode 100644 -index 000000000..5d9e76b60 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_ioctl_rtl.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_ioctl_rtl.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_ioctl_rtl.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_ioctl_rtl.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_ioctl_rtl.c 2021-03-07 18:16:17.020954446 +0200 @@ -0,0 +1,901 @@ +/****************************************************************************** + * @@ -47194,11 +44253,9 @@ index 000000000..5d9e76b60 + return status; +} +/* ************** oid_rtl_seg_03_00 section end ************** */ -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_ioctl_set.c linux-5.8/3rdparty/rtl8812au/core/rtw_ioctl_set.c -new file mode 100644 -index 000000000..1b91233fe ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_ioctl_set.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_ioctl_set.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_ioctl_set.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_ioctl_set.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_ioctl_set.c 2021-03-07 18:16:17.020954446 +0200 @@ -0,0 +1,930 @@ +/****************************************************************************** + * @@ -48130,11 +45187,9 @@ index 000000000..1b91233fe + RTW_PRINT(FUNC_ADPT_FMT" band:%d fail\n", FUNC_ADPT_ARG(adapter), band); + return _FAIL; +} -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_iol.c linux-5.8/3rdparty/rtl8812au/core/rtw_iol.c -new file mode 100644 -index 000000000..643ec6c1d ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_iol.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_iol.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_iol.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_iol.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_iol.c 2021-03-07 18:16:17.020954446 +0200 @@ -0,0 +1,394 @@ +/****************************************************************************** + * @@ -48530,11 +45585,9 @@ index 000000000..643ec6c1d + + +#endif /* CONFIG_IOL */ -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_mem.c linux-5.8/3rdparty/rtl8812au/core/rtw_mem.c -new file mode 100644 -index 000000000..d9f5652f9 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_mem.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mem.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_mem.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_mem.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_mem.c 2021-03-07 18:16:17.020954446 +0200 @@ -0,0 +1,128 @@ +/****************************************************************************** + * @@ -48664,11 +45717,9 @@ index 000000000..d9f5652f9 + +module_init(rtw_mem_init); +module_exit(rtw_mem_exit); -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_mi.c linux-5.8/3rdparty/rtl8812au/core/rtw_mi.c -new file mode 100644 -index 000000000..2a9added7 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_mi.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mi.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_mi.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_mi.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_mi.c 2021-03-07 18:16:17.020954446 +0200 @@ -0,0 +1,1571 @@ +/****************************************************************************** + * @@ -50241,11 +47292,9 @@ index 000000000..2a9added7 +#endif + return n_assoc_iface; +} -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_mlme.c linux-5.8/3rdparty/rtl8812au/core/rtw_mlme.c -new file mode 100644 -index 000000000..8cc28c648 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_mlme.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mlme.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_mlme.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_mlme.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_mlme.c 2021-03-07 18:16:17.021954493 +0200 @@ -0,0 +1,5359 @@ +/****************************************************************************** + * @@ -55606,11 +52655,9 @@ index 000000000..8cc28c648 + , MAC_ARG(ARP_TARGET_MAC_ADDR(arp)), IP_ARG(ARP_TARGET_IP_ADDR(arp))); +} + -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_mlme_ext.c linux-5.8/3rdparty/rtl8812au/core/rtw_mlme_ext.c -new file mode 100644 -index 000000000..01136fb37 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_mlme_ext.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mlme_ext.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_mlme_ext.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_mlme_ext.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_mlme_ext.c 2021-03-07 18:16:17.023954587 +0200 @@ -0,0 +1,16825 @@ +/****************************************************************************** + * @@ -72437,11 +69484,9 @@ index 000000000..01136fb37 +#endif /* CONFIG_IOCTL_CFG80211 */ +} + -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_mp.c linux-5.8/3rdparty/rtl8812au/core/rtw_mp.c -new file mode 100644 -index 000000000..aca3e8b4b ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_mp.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_mp.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_mp.c 2021-03-07 18:16:17.023954587 +0200 @@ -0,0 +1,3867 @@ +/****************************************************************************** + * @@ -76310,11 +73355,9 @@ index 000000000..aca3e8b4b + +#endif +#endif -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.8/3rdparty/rtl8812au/core/rtw_mp_ioctl.c -new file mode 100644 -index 000000000..035d2815d ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_mp_ioctl.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_mp_ioctl.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_mp_ioctl.c 2021-03-07 18:16:17.023954587 +0200 @@ -0,0 +1,2529 @@ +/****************************************************************************** + * @@ -78845,11 +75888,9 @@ index 000000000..035d2815d + return 0; +#endif +} -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_odm.c linux-5.8/3rdparty/rtl8812au/core/rtw_odm.c -new file mode 100644 -index 000000000..720418116 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_odm.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_odm.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_odm.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_odm.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_odm.c 2021-03-07 18:16:17.023954587 +0200 @@ -0,0 +1,420 @@ +/****************************************************************************** + * @@ -79271,11 +76312,9 @@ index 000000000..720418116 + +} + -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_p2p.c linux-5.8/3rdparty/rtl8812au/core/rtw_p2p.c -new file mode 100644 -index 000000000..f66fa7155 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_p2p.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_p2p.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_p2p.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_p2p.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_p2p.c 2021-03-07 18:16:17.024954635 +0200 @@ -0,0 +1,5456 @@ +/****************************************************************************** + * @@ -84733,11 +81772,9 @@ index 000000000..f66fa7155 +} + +#endif /* CONFIG_P2P */ -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_pwrctrl.c linux-5.8/3rdparty/rtl8812au/core/rtw_pwrctrl.c -new file mode 100644 -index 000000000..b7d6dca29 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_pwrctrl.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_pwrctrl.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_pwrctrl.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_pwrctrl.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_pwrctrl.c 2021-03-07 18:16:17.024954635 +0200 @@ -0,0 +1,2765 @@ +/****************************************************************************** + * @@ -87504,11 +84541,9 @@ index 000000000..b7d6dca29 + _rtw_ssmps(adapter, sta); +} + -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_recv.c linux-5.8/3rdparty/rtl8812au/core/rtw_recv.c -new file mode 100644 -index 000000000..83fa1429f ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_recv.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_recv.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_recv.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_recv.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_recv.c 2021-03-07 18:16:17.025954682 +0200 @@ -0,0 +1,5141 @@ +/****************************************************************************** + * @@ -91502,7 +88537,7 @@ index 000000000..83fa1429f + + u8 data_rate[] = { + 2, 4, 11, 22, /* CCK */ -+ 12, 18, 24, 36, 48, 72, 93, 108, /* OFDM */ ++ 12, 18, 24, 36, 48, 72, 96, 108, /* OFDM */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* HT MCS index */ + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* VHT Nss 1 */ @@ -92651,12 +89686,10 @@ index 000000000..83fa1429f + ); +} +#endif /* DBG_RX_BH_TRACKING */ -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_rf.c linux-5.8/3rdparty/rtl8812au/core/rtw_rf.c -new file mode 100644 -index 000000000..ab4c31828 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_rf.c -@@ -0,0 +1,1384 @@ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_rf.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_rf.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_rf.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_rf.c 2021-03-07 18:16:17.025954682 +0200 +@@ -0,0 +1,1394 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -92710,6 +89743,8 @@ index 000000000..ab4c31828 +}; + +u8 center_ch_5g_all[CENTER_CH_5G_ALL_NUM] = { ++ 15, 16, 17, 18, ++ 20, 24, 28, 32, +/* G00 */36, 38, 40, + 42, +/* G01 */44, 46, 48, @@ -92717,6 +89752,8 @@ index 000000000..ab4c31828 +/* G02 */52, 54, 56, + 58, +/* G03 */60, 62, 64, ++ 68, 72, 76, 80, ++ 84, 88, 92, 96, +/* G04 */100, 102, 104, + 106, +/* G05 */108, 110, 112, @@ -92737,10 +89774,14 @@ index 000000000..ab4c31828 +}; + +u8 center_ch_5g_20m[CENTER_CH_5G_20M_NUM] = { ++ 15, 16, 17, 18, ++ 20, 24, 28, 32, +/* G00 */36, 40, +/* G01 */44, 48, +/* G02 */52, 56, +/* G03 */60, 64, ++ 68, 72, 76, 80, ++ 84, 88, 92, 96, +/* G04 */100, 104, +/* G05 */108, 112, +/* G06 */116, 120, @@ -92770,6 +89811,7 @@ index 000000000..ab4c31828 +/* G13 */175 +}; + ++#if 0 +u8 center_ch_5g_20m_40m[CENTER_CH_5G_20M_NUM + CENTER_CH_5G_40M_NUM] = { +/* G00 */36, 38, 40, +/* G01 */44, 46, 48, @@ -92786,6 +89828,7 @@ index 000000000..ab4c31828 +/* G12 */165, 167, 169, +/* G13 */173, 175, 177 +}; ++#endif + +u8 op_chs_of_cch_5g_40m[CENTER_CH_5G_40M_NUM][2] = { + {36, 40}, /* 38 */ @@ -93035,15 +90078,15 @@ index 000000000..ab4c31828 + } else { + band = BAND_ON_5G; + -+ if (36 <= ch && ch <= 42) ++ if (15 <= ch && ch <= 42) + gp = 0; + else if (44 <= ch && ch <= 48) + gp = 1; + else if (50 <= ch && ch <= 58) + gp = 2; -+ else if (60 <= ch && ch <= 64) ++ else if (60 <= ch && ch <= 80) + gp = 3; -+ else if (100 <= ch && ch <= 106) ++ else if (82 <= ch && ch <= 106) + gp = 4; + else if (108 <= ch && ch <= 114) + gp = 5; @@ -94041,11 +91084,9 @@ index 000000000..ab4c31828 + + return rtw_is_long_cac_range(hi, lo, dfs_region) ? _TRUE : _FALSE; +} -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_rm.c linux-5.8/3rdparty/rtl8812au/core/rtw_rm.c -new file mode 100644 -index 000000000..6576597b1 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_rm.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_rm.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_rm.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_rm.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_rm.c 2021-03-07 18:16:17.025954682 +0200 @@ -0,0 +1,2470 @@ +/****************************************************************************** + * @@ -96517,11 +93558,9 @@ index 000000000..6576597b1 +#endif +} +#endif /* CONFIG_RTW_80211K */ -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_rm_fsm.c linux-5.8/3rdparty/rtl8812au/core/rtw_rm_fsm.c -new file mode 100644 -index 000000000..21fb323bc ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_rm_fsm.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_rm_fsm.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_rm_fsm.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_rm_fsm.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_rm_fsm.c 2021-03-07 18:16:17.025954682 +0200 @@ -0,0 +1,998 @@ +/****************************************************************************** + * @@ -97521,11 +94560,9 @@ index 000000000..21fb323bc + rm_state_run(prm, RM_EV_state_in); +} +#endif /* CONFIG_RTW_80211K */ -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_rson.c linux-5.8/3rdparty/rtl8812au/core/rtw_rson.c -new file mode 100644 -index 000000000..4fbdbb5e8 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_rson.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_rson.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_rson.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_rson.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_rson.c 2021-03-07 18:16:17.025954682 +0200 @@ -0,0 +1,595 @@ +/****************************************************************************** + * @@ -98122,11 +95159,9 @@ index 000000000..4fbdbb5e8 +} + +#endif /* CONFIG_RTW_REPEATER_SON */ -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_sdio.c linux-5.8/3rdparty/rtl8812au/core/rtw_sdio.c -new file mode 100644 -index 000000000..e8f49bfc3 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_sdio.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_sdio.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_sdio.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_sdio.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_sdio.c 2021-03-07 18:16:17.025954682 +0200 @@ -0,0 +1,130 @@ +/****************************************************************************** + * @@ -98258,11 +95293,9 @@ index 000000000..e8f49bfc3 + + return ret; +} -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_security.c linux-5.8/3rdparty/rtl8812au/core/rtw_security.c -new file mode 100644 -index 000000000..eb08ef580 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_security.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_security.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_security.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_security.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_security.c 2021-03-07 18:16:17.026954729 +0200 @@ -0,0 +1,3122 @@ +/****************************************************************************** + * @@ -101386,11 +98419,9 @@ index 000000000..eb08ef580 + return crc; +} +#endif /*CONFIG_WOWLAN*/ -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_sreset.c linux-5.8/3rdparty/rtl8812au/core/rtw_sreset.c -new file mode 100644 -index 000000000..03dba20f3 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_sreset.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_sreset.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_sreset.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_sreset.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_sreset.c 2021-03-07 18:16:17.026954729 +0200 @@ -0,0 +1,314 @@ +/****************************************************************************** + * @@ -101706,11 +98737,9 @@ index 000000000..03dba20f3 + psrtpriv->rx_cnt = 0; +#endif +} -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_sta_mgt.c linux-5.8/3rdparty/rtl8812au/core/rtw_sta_mgt.c -new file mode 100644 -index 000000000..f8c390dec ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_sta_mgt.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_sta_mgt.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_sta_mgt.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_sta_mgt.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_sta_mgt.c 2021-03-07 18:16:17.026954729 +0200 @@ -0,0 +1,1323 @@ +/****************************************************************************** + * @@ -103035,11 +100064,9 @@ index 000000000..f8c390dec +} +#endif /* CONFIG_RTW_PRE_LINK_STA */ + -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_tdls.c linux-5.8/3rdparty/rtl8812au/core/rtw_tdls.c -new file mode 100644 -index 000000000..4cb38921c ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_tdls.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_tdls.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_tdls.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_tdls.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_tdls.c 2021-03-07 18:16:17.026954729 +0200 @@ -0,0 +1,3505 @@ +/****************************************************************************** + * @@ -106546,1152 +103573,9 @@ index 000000000..4cb38921c +} + +#endif /* CONFIG_TDLS */ -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_vht.c linux-5.8/3rdparty/rtl8812au/core/rtw_vht.c -new file mode 100644 -index 000000000..9a7608c8e ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_vht.c -@@ -0,0 +1,1135 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+#define _RTW_VHT_C -+ -+#include -+#include -+ -+#ifdef CONFIG_80211AC_VHT -+const u16 _vht_max_mpdu_len[] = { -+ 3895, -+ 7991, -+ 11454, -+ 0, -+}; -+ -+const u8 _vht_sup_ch_width_set_to_bw_cap[] = { -+ BW_CAP_80M, -+ BW_CAP_80M | BW_CAP_160M, -+ BW_CAP_80M | BW_CAP_160M | BW_CAP_80_80M, -+ 0, -+}; -+ -+const char *const _vht_sup_ch_width_set_str[] = { -+ "80MHz", -+ "160MHz", -+ "160MHz & 80+80MHz", -+ "BW-RSVD", -+}; -+ -+void dump_vht_cap_ie_content(void *sel, const u8 *buf, u32 buf_len) -+{ -+ if (buf_len != VHT_CAP_IE_LEN) { -+ RTW_PRINT_SEL(sel, "Invalid VHT capability IE len:%d != %d\n", buf_len, VHT_CAP_IE_LEN); -+ return; -+ } -+ -+ RTW_PRINT_SEL(sel, "cap_info:%02x %02x %02x %02x: MAX_MPDU_LEN:%u %s%s%s%s%s RX-STBC:%u MAX_AMPDU_LEN:%u\n" -+ , *(buf), *(buf + 1), *(buf + 2), *(buf + 3) -+ , vht_max_mpdu_len(GET_VHT_CAPABILITY_ELE_MAX_MPDU_LENGTH(buf)) -+ , vht_sup_ch_width_set_str(GET_VHT_CAPABILITY_ELE_CHL_WIDTH(buf)) -+ , GET_VHT_CAPABILITY_ELE_RX_LDPC(buf) ? " RX-LDPC" : "" -+ , GET_VHT_CAPABILITY_ELE_SHORT_GI80M(buf) ? " SGI-80" : "" -+ , GET_VHT_CAPABILITY_ELE_SHORT_GI160M(buf) ? " SGI-160" : "" -+ , GET_VHT_CAPABILITY_ELE_TX_STBC(buf) ? " TX-STBC" : "" -+ , GET_VHT_CAPABILITY_ELE_RX_STBC(buf) -+ , VHT_MAX_AMPDU_LEN(GET_VHT_CAPABILITY_ELE_MAX_RXAMPDU_FACTOR(buf)) -+ ); -+} -+ -+void dump_vht_cap_ie(void *sel, const u8 *ie, u32 ie_len) -+{ -+ const u8 *vht_cap_ie; -+ sint vht_cap_ielen; -+ -+ vht_cap_ie = rtw_get_ie(ie, WLAN_EID_VHT_CAPABILITY, &vht_cap_ielen, ie_len); -+ if (!ie || vht_cap_ie != ie) -+ return; -+ -+ dump_vht_cap_ie_content(sel, vht_cap_ie + 2, vht_cap_ielen); -+} -+ -+const char *const _vht_op_ch_width_str[] = { -+ "20 or 40MHz", -+ "80MHz", -+ "160MHz", -+ "80+80MHz", -+ "BW-RSVD", -+}; -+ -+void dump_vht_op_ie_content(void *sel, const u8 *buf, u32 buf_len) -+{ -+ if (buf_len != VHT_OP_IE_LEN) { -+ RTW_PRINT_SEL(sel, "Invalid VHT operation IE len:%d != %d\n", buf_len, VHT_OP_IE_LEN); -+ return; -+ } -+ -+ RTW_PRINT_SEL(sel, "%s, ch0:%u, ch1:%u\n" -+ , vht_op_ch_width_str(GET_VHT_OPERATION_ELE_CHL_WIDTH(buf)) -+ , GET_VHT_OPERATION_ELE_CENTER_FREQ1(buf) -+ , GET_VHT_OPERATION_ELE_CENTER_FREQ2(buf) -+ ); -+} -+ -+void dump_vht_op_ie(void *sel, const u8 *ie, u32 ie_len) -+{ -+ const u8 *vht_op_ie; -+ sint vht_op_ielen; -+ -+ vht_op_ie = rtw_get_ie(ie, WLAN_EID_VHT_OPERATION, &vht_op_ielen, ie_len); -+ if (!ie || vht_op_ie != ie) -+ return; -+ -+ dump_vht_op_ie_content(sel, vht_op_ie + 2, vht_op_ielen); -+} -+ -+/* 20/40/80, ShortGI, MCS Rate */ -+const u16 VHT_MCS_DATA_RATE[3][2][30] = { -+ { { -+ 13, 26, 39, 52, 78, 104, 117, 130, 156, 156, -+ 26, 52, 78, 104, 156, 208, 234, 260, 312, 312, -+ 39, 78, 117, 156, 234, 312, 351, 390, 468, 520 -+ }, /* Long GI, 20MHz */ -+ { -+ 14, 29, 43, 58, 87, 116, 130, 144, 173, 173, -+ 29, 58, 87, 116, 173, 231, 260, 289, 347, 347, -+ 43, 87, 130, 173, 260, 347, 390, 433, 520, 578 -+ } -+ }, /* Short GI, 20MHz */ -+ { { -+ 27, 54, 81, 108, 162, 216, 243, 270, 324, 360, -+ 54, 108, 162, 216, 324, 432, 486, 540, 648, 720, -+ 81, 162, 243, 324, 486, 648, 729, 810, 972, 1080 -+ }, /* Long GI, 40MHz */ -+ { -+ 30, 60, 90, 120, 180, 240, 270, 300, 360, 400, -+ 60, 120, 180, 240, 360, 480, 540, 600, 720, 800, -+ 90, 180, 270, 360, 540, 720, 810, 900, 1080, 1200 -+ } -+ }, /* Short GI, 40MHz */ -+ { { -+ 59, 117, 176, 234, 351, 468, 527, 585, 702, 780, -+ 117, 234, 351, 468, 702, 936, 1053, 1170, 1404, 1560, -+ 176, 351, 527, 702, 1053, 1404, 1580, 1755, 2106, 2340 -+ }, /* Long GI, 80MHz */ -+ { -+ 65, 130, 195, 260, 390, 520, 585, 650, 780, 867, -+ 130, 260, 390, 520, 780, 1040, 1170, 1300, 1560, 1734, -+ 195, 390, 585, 780, 1170, 1560, 1755, 1950, 2340, 2600 -+ } -+ } /* Short GI, 80MHz */ -+}; -+ -+u8 rtw_get_vht_highest_rate(u8 *pvht_mcs_map) -+{ -+ u8 i, j; -+ u8 bit_map; -+ u8 vht_mcs_rate = 0; -+ -+ for (i = 0; i < 2; i++) { -+ if (pvht_mcs_map[i] != 0xff) { -+ for (j = 0; j < 8; j += 2) { -+ bit_map = (pvht_mcs_map[i] >> j) & 3; -+ -+ if (bit_map != 3) -+ vht_mcs_rate = MGN_VHT1SS_MCS7 + 10 * j / 2 + i * 40 + bit_map; /* VHT rate indications begin from 0x90 */ -+ } -+ } -+ } -+ -+ /* RTW_INFO("HighestVHTMCSRate is %x\n", vht_mcs_rate); */ -+ return vht_mcs_rate; -+} -+ -+u8 rtw_vht_mcsmap_to_nss(u8 *pvht_mcs_map) -+{ -+ u8 i, j; -+ u8 bit_map; -+ u8 nss = 0; -+ -+ for (i = 0; i < 2; i++) { -+ if (pvht_mcs_map[i] != 0xff) { -+ for (j = 0; j < 8; j += 2) { -+ bit_map = (pvht_mcs_map[i] >> j) & 3; -+ -+ if (bit_map != 3) -+ nss++; -+ } -+ } -+ } -+ -+ /* RTW_INFO("%s : %dSS\n", __FUNCTION__, nss); */ -+ return nss; -+} -+ -+void rtw_vht_nss_to_mcsmap(u8 nss, u8 *target_mcs_map, u8 *cur_mcs_map) -+{ -+ u8 i, j; -+ u8 cur_rate, target_rate; -+ -+ for (i = 0; i < 2; i++) { -+ target_mcs_map[i] = 0; -+ for (j = 0; j < 8; j += 2) { -+ cur_rate = (cur_mcs_map[i] >> j) & 3; -+ if (cur_rate == 3) /* 0x3 indicates not supported that num of SS */ -+ target_rate = 3; -+ else if (nss <= ((j / 2) + i * 4)) -+ target_rate = 3; -+ else -+ target_rate = cur_rate; -+ -+ target_mcs_map[i] |= (target_rate << j); -+ } -+ } -+ -+ /* RTW_INFO("%s : %dSS\n", __FUNCTION__, nss); */ -+} -+ -+u16 rtw_vht_mcs_to_data_rate(u8 bw, u8 short_GI, u8 vht_mcs_rate) -+{ -+ if (vht_mcs_rate > MGN_VHT3SS_MCS9) -+ vht_mcs_rate = MGN_VHT3SS_MCS9; -+ /* RTW_INFO("bw=%d, short_GI=%d, ((vht_mcs_rate - MGN_VHT1SS_MCS0)&0x3f)=%d\n", bw, short_GI, ((vht_mcs_rate - MGN_VHT1SS_MCS0)&0x3f)); */ -+ return VHT_MCS_DATA_RATE[bw][short_GI][((vht_mcs_rate - MGN_VHT1SS_MCS0) & 0x3f)]; -+} -+ -+void rtw_vht_use_default_setting(_adapter *padapter) -+{ -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; -+ struct registry_priv *pregistrypriv = &padapter->registrypriv; -+ BOOLEAN bHwLDPCSupport = _FALSE, bHwSTBCSupport = _FALSE; -+#ifdef CONFIG_BEAMFORMING -+ BOOLEAN bHwSupportBeamformer = _FALSE, bHwSupportBeamformee = _FALSE; -+ u8 mu_bfer, mu_bfee; -+#endif /* CONFIG_BEAMFORMING */ -+ u8 rf_type = 0; -+ u8 tx_nss, rx_nss; -+ struct hal_spec_t *hal_spec = GET_HAL_SPEC(padapter); -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ pvhtpriv->sgi_80m = TEST_FLAG(pregistrypriv->short_gi, BIT2) ? _TRUE : _FALSE; -+ -+ /* LDPC support */ -+ rtw_hal_get_def_var(padapter, HAL_DEF_RX_LDPC, (u8 *)&bHwLDPCSupport); -+ CLEAR_FLAGS(pvhtpriv->ldpc_cap); -+ if (bHwLDPCSupport) { -+ if (TEST_FLAG(pregistrypriv->ldpc_cap, BIT0)) -+ SET_FLAG(pvhtpriv->ldpc_cap, LDPC_VHT_ENABLE_RX); -+ } -+ rtw_hal_get_def_var(padapter, HAL_DEF_TX_LDPC, (u8 *)&bHwLDPCSupport); -+ if (bHwLDPCSupport) { -+ if (TEST_FLAG(pregistrypriv->ldpc_cap, BIT1)) -+ SET_FLAG(pvhtpriv->ldpc_cap, LDPC_VHT_ENABLE_TX); -+ } -+ if (pvhtpriv->ldpc_cap) -+ RTW_INFO("[VHT] Support LDPC = 0x%02X\n", pvhtpriv->ldpc_cap); -+ -+ /* STBC */ -+ rtw_hal_get_def_var(padapter, HAL_DEF_TX_STBC, (u8 *)&bHwSTBCSupport); -+ CLEAR_FLAGS(pvhtpriv->stbc_cap); -+ if (bHwSTBCSupport) { -+ if (TEST_FLAG(pregistrypriv->stbc_cap, BIT1)) -+ SET_FLAG(pvhtpriv->stbc_cap, STBC_VHT_ENABLE_TX); -+ } -+ rtw_hal_get_def_var(padapter, HAL_DEF_RX_STBC, (u8 *)&bHwSTBCSupport); -+ if (bHwSTBCSupport) { -+ if (TEST_FLAG(pregistrypriv->stbc_cap, BIT0)) -+ SET_FLAG(pvhtpriv->stbc_cap, STBC_VHT_ENABLE_RX); -+ } -+ if (pvhtpriv->stbc_cap) -+ RTW_INFO("[VHT] Support STBC = 0x%02X\n", pvhtpriv->stbc_cap); -+ -+ /* Beamforming setting */ -+ CLEAR_FLAGS(pvhtpriv->beamform_cap); -+#ifdef CONFIG_BEAMFORMING -+#ifdef RTW_BEAMFORMING_VERSION_2 -+ /* only enable beamforming in STA client mode */ -+ if (MLME_IS_STA(padapter) && !MLME_IS_GC(padapter) -+ && !MLME_IS_ADHOC(padapter) -+ && !MLME_IS_MESH(padapter)) -+#endif -+ { -+ rtw_hal_get_def_var(padapter, HAL_DEF_EXPLICIT_BEAMFORMER, -+ (u8 *)&bHwSupportBeamformer); -+ rtw_hal_get_def_var(padapter, HAL_DEF_EXPLICIT_BEAMFORMEE, -+ (u8 *)&bHwSupportBeamformee); -+ mu_bfer = _FALSE; -+ mu_bfee = _FALSE; -+ rtw_hal_get_def_var(padapter, HAL_DEF_VHT_MU_BEAMFORMER, &mu_bfer); -+ rtw_hal_get_def_var(padapter, HAL_DEF_VHT_MU_BEAMFORMEE, &mu_bfee); -+ if (TEST_FLAG(pregistrypriv->beamform_cap, BIT0) && bHwSupportBeamformer) { -+#ifdef CONFIG_CONCURRENT_MODE -+ if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) { -+ SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE); -+ RTW_INFO("[VHT] CONCURRENT AP Support Beamformer\n"); -+ if (TEST_FLAG(pregistrypriv->beamform_cap, BIT(2)) -+ && (_TRUE == mu_bfer)) { -+ SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE); -+ RTW_INFO("[VHT] Support MU-MIMO AP\n"); -+ } -+ } else -+ RTW_INFO("[VHT] CONCURRENT not AP ;not allow Support Beamformer\n"); -+#else -+ SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE); -+ RTW_INFO("[VHT] Support Beamformer\n"); -+ if (TEST_FLAG(pregistrypriv->beamform_cap, BIT(2)) -+ && (_TRUE == mu_bfer) -+ && ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) { -+ SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE); -+ RTW_INFO("[VHT] Support MU-MIMO AP\n"); -+ } -+#endif -+ } -+ if (TEST_FLAG(pregistrypriv->beamform_cap, BIT1) && bHwSupportBeamformee) { -+ SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE); -+ RTW_INFO("[VHT] Support Beamformee\n"); -+ if (TEST_FLAG(pregistrypriv->beamform_cap, BIT(3)) -+ && (_TRUE == mu_bfee) -+ && ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE)) { -+ SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE); -+ RTW_INFO("[VHT] Support MU-MIMO STA\n"); -+ } -+ } -+ } -+#endif /* CONFIG_BEAMFORMING */ -+ -+ pvhtpriv->ampdu_len = pregistrypriv->ampdu_factor; -+ -+ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); -+ tx_nss = rtw_min(rf_type_to_rf_tx_cnt(rf_type), hal_spec->tx_nss_num); -+ rx_nss = rtw_min(rf_type_to_rf_rx_cnt(rf_type), hal_spec->rx_nss_num); -+ -+ /* for now, vhtpriv.vht_mcs_map comes from RX NSS */ -+ rtw_vht_nss_to_mcsmap(rx_nss, pvhtpriv->vht_mcs_map, pregistrypriv->vht_rx_mcs_map); -+ pvhtpriv->vht_highest_rate = rtw_get_vht_highest_rate(pvhtpriv->vht_mcs_map); -+} -+ -+u64 rtw_vht_mcs_map_to_bitmap(u8 *mcs_map, u8 nss) -+{ -+ u8 i, j, tmp; -+ u64 bitmap = 0; -+ u8 bits_nss = nss * 2; -+ -+ for (i = j = 0; i < bits_nss; i += 2, j += 10) { -+ /* every two bits means single sptial stream */ -+ tmp = (mcs_map[i / 8] >> i) & 3; -+ -+ switch (tmp) { -+ case 2: -+ bitmap = bitmap | (0x03ff << j); -+ break; -+ case 1: -+ bitmap = bitmap | (0x01ff << j); -+ break; -+ case 0: -+ bitmap = bitmap | (0x00ff << j); -+ break; -+ default: -+ break; -+ } -+ } -+ -+ RTW_INFO("vht_mcs_map=%02x %02x, nss=%u => bitmap=%016llx\n" -+ , mcs_map[0], mcs_map[1], nss, bitmap); -+ -+ return bitmap; -+} -+ -+#ifdef CONFIG_BEAMFORMING -+void update_sta_vht_info_apmode_bf_cap(_adapter *padapter, struct sta_info *psta) -+{ -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ struct vht_priv *pvhtpriv_ap = &pmlmepriv->vhtpriv; -+ struct vht_priv *pvhtpriv_sta = &psta->vhtpriv; -+ u16 cur_beamform_cap = 0; -+ -+ /* B11 SU Beamformer Capable, the target supports Beamformer and we are Beamformee */ -+ if (TEST_FLAG(pvhtpriv_ap->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE) && -+ GET_VHT_CAPABILITY_ELE_SU_BFEE(pvhtpriv_sta->vht_cap)) { -+ SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE); -+ /*Shift to BEAMFORMING_VHT_BEAMFORMER_STS_CAP*/ -+ SET_FLAG(cur_beamform_cap, GET_VHT_CAPABILITY_ELE_SU_BFEE_STS_CAP(pvhtpriv_sta->vht_cap) << 8); -+ } -+ -+ /* B12 SU Beamformee Capable, the target supports Beamformee and we are Beamformer */ -+ if (TEST_FLAG(pvhtpriv_ap->beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE) && -+ GET_VHT_CAPABILITY_ELE_SU_BFER(pvhtpriv_sta->vht_cap)) { -+ SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE); -+ /*Shit to BEAMFORMING_VHT_BEAMFORMEE_SOUND_DIM*/ -+ SET_FLAG(cur_beamform_cap, GET_VHT_CAPABILITY_ELE_SU_BFER_SOUND_DIM_NUM(pvhtpriv_sta->vht_cap) << 12); -+ } -+ -+ if (cur_beamform_cap) -+ RTW_INFO("Current STA(%d) VHT Beamforming Setting = %02X\n", psta->cmn.aid, cur_beamform_cap); -+ -+ pvhtpriv_sta->beamform_cap = cur_beamform_cap; -+ psta->cmn.bf_info.vht_beamform_cap = cur_beamform_cap; -+} -+#endif -+ -+void update_sta_vht_info_apmode(_adapter *padapter, PVOID sta) -+{ -+ struct sta_info *psta = (struct sta_info *)sta; -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct vht_priv *pvhtpriv_ap = &pmlmepriv->vhtpriv; -+ struct vht_priv *pvhtpriv_sta = &psta->vhtpriv; -+ u8 cur_ldpc_cap = 0, cur_stbc_cap = 0; -+ s8 bw_mode = -1; -+ u8 *pcap_mcs; -+ -+ if (pvhtpriv_sta->vht_option == _FALSE) -+ return; -+ -+ if (pvhtpriv_sta->op_present) { -+ switch (GET_VHT_OPERATION_ELE_CHL_WIDTH(pvhtpriv_sta->vht_op)) { -+ case 1: /* 80MHz */ -+ case 2: /* 160MHz */ -+ case 3: /* 80+80 */ -+ bw_mode = CHANNEL_WIDTH_80; /* only support up to 80MHz for now */ -+ break; -+ } -+ } -+ -+ if (pvhtpriv_sta->notify_present) -+ bw_mode = GET_VHT_OPERATING_MODE_FIELD_CHNL_WIDTH(&pvhtpriv_sta->vht_op_mode_notify); -+ else if (MLME_IS_AP(padapter)) { -+ /* for VHT client without Operating Mode Notify IE; minimal 80MHz */ -+ if (bw_mode < CHANNEL_WIDTH_80) -+ bw_mode = CHANNEL_WIDTH_80; -+ } -+ -+ if (bw_mode != -1) -+ psta->cmn.bw_mode = bw_mode; /* update bw_mode only if get value from VHT IEs */ -+ -+ psta->cmn.ra_info.is_vht_enable = _TRUE; -+ -+ /* B4 Rx LDPC */ -+ if (TEST_FLAG(pvhtpriv_ap->ldpc_cap, LDPC_VHT_ENABLE_TX) && -+ GET_VHT_CAPABILITY_ELE_RX_LDPC(pvhtpriv_sta->vht_cap)) { -+ SET_FLAG(cur_ldpc_cap, (LDPC_VHT_ENABLE_TX | LDPC_VHT_CAP_TX)); -+ RTW_INFO("Current STA(%d) VHT LDPC = %02X\n", psta->cmn.aid, cur_ldpc_cap); -+ } -+ pvhtpriv_sta->ldpc_cap = cur_ldpc_cap; -+ -+ if (psta->cmn.bw_mode > pmlmeext->cur_bwmode) -+ psta->cmn.bw_mode = pmlmeext->cur_bwmode; -+ -+ if (psta->cmn.bw_mode == CHANNEL_WIDTH_80) { -+ /* B5 Short GI for 80 MHz */ -+ pvhtpriv_sta->sgi_80m = (GET_VHT_CAPABILITY_ELE_SHORT_GI80M(pvhtpriv_sta->vht_cap) & pvhtpriv_ap->sgi_80m) ? _TRUE : _FALSE; -+ /* RTW_INFO("Current STA ShortGI80MHz = %d\n", pvhtpriv_sta->sgi_80m); */ -+ } else if (psta->cmn.bw_mode >= CHANNEL_WIDTH_160) { -+ /* B5 Short GI for 80 MHz */ -+ pvhtpriv_sta->sgi_80m = (GET_VHT_CAPABILITY_ELE_SHORT_GI160M(pvhtpriv_sta->vht_cap) & pvhtpriv_ap->sgi_80m) ? _TRUE : _FALSE; -+ /* RTW_INFO("Current STA ShortGI160MHz = %d\n", pvhtpriv_sta->sgi_80m); */ -+ } -+ -+ /* B8 B9 B10 Rx STBC */ -+ if (TEST_FLAG(pvhtpriv_ap->stbc_cap, STBC_VHT_ENABLE_TX) && -+ GET_VHT_CAPABILITY_ELE_RX_STBC(pvhtpriv_sta->vht_cap)) { -+ SET_FLAG(cur_stbc_cap, (STBC_VHT_ENABLE_TX | STBC_VHT_CAP_TX)); -+ RTW_INFO("Current STA(%d) VHT STBC = %02X\n", psta->cmn.aid, cur_stbc_cap); -+ } -+ pvhtpriv_sta->stbc_cap = cur_stbc_cap; -+ -+#ifdef CONFIG_BEAMFORMING -+ update_sta_vht_info_apmode_bf_cap(padapter, psta); -+#endif -+ -+ /* B23 B24 B25 Maximum A-MPDU Length Exponent */ -+ pvhtpriv_sta->ampdu_len = GET_VHT_CAPABILITY_ELE_MAX_RXAMPDU_FACTOR(pvhtpriv_sta->vht_cap); -+ -+ pcap_mcs = GET_VHT_CAPABILITY_ELE_RX_MCS(pvhtpriv_sta->vht_cap); -+ _rtw_memcpy(pvhtpriv_sta->vht_mcs_map, pcap_mcs, 2); -+ pvhtpriv_sta->vht_highest_rate = rtw_get_vht_highest_rate(pvhtpriv_sta->vht_mcs_map); -+} -+ -+void update_hw_vht_param(_adapter *padapter) -+{ -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ u8 ht_AMPDU_len; -+ -+ ht_AMPDU_len = pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x03; -+ -+ if (pvhtpriv->ampdu_len > ht_AMPDU_len) -+ rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&pvhtpriv->ampdu_len)); -+} -+ -+#ifdef ROKU_PRIVATE -+u8 VHT_get_ss_from_map(u8 *vht_mcs_map) -+{ -+ u8 i, j; -+ u8 ss = 0; -+ -+ for (i = 0; i < 2; i++) { -+ if (vht_mcs_map[i] != 0xff) { -+ for (j = 0; j < 8; j += 2) { -+ if (((vht_mcs_map[i] >> j) & 0x03) == 0x03) -+ break; -+ ss++; -+ } -+ } -+ -+ } -+ -+return ss; -+} -+ -+void VHT_caps_handler_infra_ap(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE) -+{ -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct vht_priv_infra_ap *pvhtpriv = &pmlmepriv->vhtpriv_infra_ap; -+ u8 cur_stbc_cap_infra_ap = 0; -+ u16 cur_beamform_cap_infra_ap = 0; -+ u8 *pcap_mcs; -+ u8 *pcap_mcs_tx; -+ u8 Rx_ss = 0, Tx_ss = 0; -+ -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ if (pIE == NULL) -+ return; -+ -+ pmlmeinfo->ht_vht_received |= BIT(1); -+ -+ pvhtpriv->ldpc_cap_infra_ap = GET_VHT_CAPABILITY_ELE_RX_LDPC(pIE->data); -+ -+ if (GET_VHT_CAPABILITY_ELE_RX_STBC(pIE->data)) -+ SET_FLAG(cur_stbc_cap_infra_ap, STBC_VHT_ENABLE_RX); -+ if (GET_VHT_CAPABILITY_ELE_TX_STBC(pIE->data)) -+ SET_FLAG(cur_stbc_cap_infra_ap, STBC_VHT_ENABLE_TX); -+ pvhtpriv->stbc_cap_infra_ap = cur_stbc_cap_infra_ap; -+ -+ /*store ap info for channel bandwidth*/ -+ pvhtpriv->channel_width_infra_ap = GET_VHT_CAPABILITY_ELE_CHL_WIDTH(pIE->data); -+ -+ /*check B11: SU Beamformer Capable and B12: SU Beamformee B19: MU Beamformer B20:MU Beamformee*/ -+ if (GET_VHT_CAPABILITY_ELE_SU_BFER(pIE->data)) -+ SET_FLAG(cur_beamform_cap_infra_ap, BEAMFORMING_VHT_BEAMFORMER_ENABLE); -+ if (GET_VHT_CAPABILITY_ELE_SU_BFEE(pIE->data)) -+ SET_FLAG(cur_beamform_cap_infra_ap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE); -+ if (GET_VHT_CAPABILITY_ELE_MU_BFER(pIE->data)) -+ SET_FLAG(cur_beamform_cap_infra_ap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE); -+ if (GET_VHT_CAPABILITY_ELE_MU_BFEE(pIE->data)) -+ SET_FLAG(cur_beamform_cap_infra_ap, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE); -+ pvhtpriv->beamform_cap_infra_ap = cur_beamform_cap_infra_ap; -+ -+ /*store information about vht_mcs_set*/ -+ pcap_mcs = GET_VHT_CAPABILITY_ELE_RX_MCS(pIE->data); -+ pcap_mcs_tx = GET_VHT_CAPABILITY_ELE_TX_MCS(pIE->data); -+ _rtw_memcpy(pvhtpriv->vht_mcs_map_infra_ap, pcap_mcs, 2); -+ _rtw_memcpy(pvhtpriv->vht_mcs_map_tx_infra_ap, pcap_mcs_tx, 2); -+ -+ Rx_ss = VHT_get_ss_from_map(pvhtpriv->vht_mcs_map_infra_ap); -+ Tx_ss = VHT_get_ss_from_map(pvhtpriv->vht_mcs_map_tx_infra_ap); -+ if (Rx_ss >= Tx_ss) { -+ pvhtpriv->number_of_streams_infra_ap = Rx_ss; -+ } else{ -+ pvhtpriv->number_of_streams_infra_ap = Tx_ss; -+ } -+ -+} -+#endif /* ROKU_PRIVATE */ -+ -+void VHT_caps_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE) -+{ -+ struct hal_spec_t *hal_spec = GET_HAL_SPEC(padapter); -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ u8 cur_ldpc_cap = 0, cur_stbc_cap = 0, rf_type = RF_1T1R, tx_nss = 0; -+ u16 cur_beamform_cap = 0; -+ u8 *pcap_mcs; -+ -+ if (pIE == NULL) -+ return; -+ -+ if (pvhtpriv->vht_option == _FALSE) -+ return; -+ -+ pmlmeinfo->VHT_enable = 1; -+ -+ /* B4 Rx LDPC */ -+ if (TEST_FLAG(pvhtpriv->ldpc_cap, LDPC_VHT_ENABLE_TX) && -+ GET_VHT_CAPABILITY_ELE_RX_LDPC(pIE->data)) { -+ SET_FLAG(cur_ldpc_cap, (LDPC_VHT_ENABLE_TX | LDPC_VHT_CAP_TX)); -+ RTW_INFO("Current VHT LDPC Setting = %02X\n", cur_ldpc_cap); -+ } -+ pvhtpriv->ldpc_cap = cur_ldpc_cap; -+ -+ /* B5 Short GI for 80 MHz */ -+ pvhtpriv->sgi_80m = (GET_VHT_CAPABILITY_ELE_SHORT_GI80M(pIE->data) & pvhtpriv->sgi_80m) ? _TRUE : _FALSE; -+ /* RTW_INFO("Current ShortGI80MHz = %d\n", pvhtpriv->sgi_80m); */ -+ -+ /* B8 B9 B10 Rx STBC */ -+ if (TEST_FLAG(pvhtpriv->stbc_cap, STBC_VHT_ENABLE_TX) && -+ GET_VHT_CAPABILITY_ELE_RX_STBC(pIE->data)) { -+ SET_FLAG(cur_stbc_cap, (STBC_VHT_ENABLE_TX | STBC_VHT_CAP_TX)); -+ RTW_INFO("Current VHT STBC Setting = %02X\n", cur_stbc_cap); -+ } -+ pvhtpriv->stbc_cap = cur_stbc_cap; -+#ifdef CONFIG_BEAMFORMING -+#ifdef RTW_BEAMFORMING_VERSION_2 -+ /* -+ * B11 SU Beamformer Capable, -+ * the target supports Beamformer and we are Beamformee -+ */ -+ if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE) -+ && GET_VHT_CAPABILITY_ELE_SU_BFER(pIE->data)) { -+ SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE); -+ -+ /* Shift to BEAMFORMING_VHT_BEAMFORMEE_STS_CAP */ -+ SET_FLAG(cur_beamform_cap, GET_VHT_CAPABILITY_ELE_SU_BFEE_STS_CAP(pIE->data) << 8); -+ -+ /* -+ * B19 MU Beamformer Capable, -+ * the target supports Beamformer and we are Beamformee -+ */ -+ if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE) -+ && GET_VHT_CAPABILITY_ELE_MU_BFER(pIE->data)) -+ SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE); -+ } -+ -+ /* -+ * B12 SU Beamformee Capable, -+ * the target supports Beamformee and we are Beamformer -+ */ -+ if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE) -+ && GET_VHT_CAPABILITY_ELE_SU_BFEE(pIE->data)) { -+ SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE); -+ -+ /* Shit to BEAMFORMING_VHT_BEAMFORMER_SOUND_DIM */ -+ SET_FLAG(cur_beamform_cap, GET_VHT_CAPABILITY_ELE_SU_BFER_SOUND_DIM_NUM(pIE->data) << 12); -+ -+ /* -+ * B20 MU Beamformee Capable, -+ * the target supports Beamformee and we are Beamformer -+ */ -+ if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE) -+ && GET_VHT_CAPABILITY_ELE_MU_BFEE(pIE->data)) -+ SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE); -+ } -+ -+ pvhtpriv->beamform_cap = cur_beamform_cap; -+ RTW_INFO("Current VHT Beamforming Setting=0x%04X\n", cur_beamform_cap); -+#else /* !RTW_BEAMFORMING_VERSION_2 */ -+ /* B11 SU Beamformer Capable, the target supports Beamformer and we are Beamformee */ -+ if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE) && -+ GET_VHT_CAPABILITY_ELE_SU_BFEE(pIE->data)) { -+ SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE); -+ /*Shift to BEAMFORMING_VHT_BEAMFORMER_STS_CAP*/ -+ SET_FLAG(cur_beamform_cap, GET_VHT_CAPABILITY_ELE_SU_BFEE_STS_CAP(pIE->data) << 8); -+ } -+ -+ /* B12 SU Beamformee Capable, the target supports Beamformee and we are Beamformer */ -+ if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE) && -+ GET_VHT_CAPABILITY_ELE_SU_BFER(pIE->data)) { -+ SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE); -+ /*Shit to BEAMFORMING_VHT_BEAMFORMEE_SOUND_DIM*/ -+ SET_FLAG(cur_beamform_cap, GET_VHT_CAPABILITY_ELE_SU_BFER_SOUND_DIM_NUM(pIE->data) << 12); -+ -+ } -+ pvhtpriv->beamform_cap = cur_beamform_cap; -+ if (cur_beamform_cap) -+ RTW_INFO("Current VHT Beamforming Setting = %02X\n", cur_beamform_cap); -+#endif /* !RTW_BEAMFORMING_VERSION_2 */ -+#endif /* CONFIG_BEAMFORMING */ -+ /* B23 B24 B25 Maximum A-MPDU Length Exponent */ -+ pvhtpriv->ampdu_len = GET_VHT_CAPABILITY_ELE_MAX_RXAMPDU_FACTOR(pIE->data); -+ -+ pcap_mcs = GET_VHT_CAPABILITY_ELE_RX_MCS(pIE->data); -+ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); -+ tx_nss = rtw_min(rf_type_to_rf_tx_cnt(rf_type), hal_spec->tx_nss_num); -+ rtw_vht_nss_to_mcsmap(tx_nss, pvhtpriv->vht_mcs_map, pcap_mcs); -+ pvhtpriv->vht_highest_rate = rtw_get_vht_highest_rate(pvhtpriv->vht_mcs_map); -+} -+ -+void VHT_operation_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE) -+{ -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; -+ -+ if (pIE == NULL) -+ return; -+ -+ if (pvhtpriv->vht_option == _FALSE) -+ return; -+} -+ -+void rtw_process_vht_op_mode_notify(_adapter *padapter, u8 *pframe, PVOID sta) -+{ -+ struct sta_info *psta = (struct sta_info *)sta; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; -+ struct registry_priv *regsty = adapter_to_regsty(padapter); -+ u8 target_bw; -+ u8 target_rxss, current_rxss; -+ u8 update_ra = _FALSE; -+ u8 tx_nss = 0, rf_type = RF_1T1R; -+ struct hal_spec_t *hal_spec = GET_HAL_SPEC(padapter); -+ -+ if (pvhtpriv->vht_option == _FALSE) -+ return; -+ -+ target_bw = GET_VHT_OPERATING_MODE_FIELD_CHNL_WIDTH(pframe); -+ -+ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); -+ tx_nss = rtw_min(rf_type_to_rf_tx_cnt(rf_type), hal_spec->tx_nss_num); -+ target_rxss = rtw_min(tx_nss, (GET_VHT_OPERATING_MODE_FIELD_RX_NSS(pframe) + 1)); -+ -+ if (target_bw != psta->cmn.bw_mode) { -+ if (hal_is_bw_support(padapter, target_bw) -+ && REGSTY_IS_BW_5G_SUPPORT(regsty, target_bw) -+ ) { -+ update_ra = _TRUE; -+ psta->cmn.bw_mode = target_bw; -+ } -+ } -+ -+ current_rxss = rtw_vht_mcsmap_to_nss(psta->vhtpriv.vht_mcs_map); -+ if (target_rxss != current_rxss) { -+ u8 vht_mcs_map[2] = {}; -+ -+ update_ra = _TRUE; -+ -+ rtw_vht_nss_to_mcsmap(target_rxss, vht_mcs_map, psta->vhtpriv.vht_mcs_map); -+ _rtw_memcpy(psta->vhtpriv.vht_mcs_map, vht_mcs_map, 2); -+ -+ rtw_hal_update_sta_ra_info(padapter, psta); -+ } -+ -+ if (update_ra) -+ rtw_dm_ra_mask_wk_cmd(padapter, (u8 *)psta); -+} -+ -+u32 rtw_build_vht_operation_ie(_adapter *padapter, u8 *pbuf, u8 channel) -+{ -+ struct registry_priv *pregistrypriv = &padapter->registrypriv; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; -+ /* struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; */ -+ u8 ChnlWidth, center_freq, bw_mode; -+ u32 len = 0; -+ u8 operation[5]; -+ -+ _rtw_memset(operation, 0, 5); -+ -+ bw_mode = REGSTY_BW_5G(pregistrypriv); /* TODO: control op bw with other info */ -+ -+ if (hal_chk_bw_cap(padapter, BW_CAP_80M | BW_CAP_160M) -+ && REGSTY_BW_5G(pregistrypriv) >= CHANNEL_WIDTH_80 -+ ) { -+ center_freq = rtw_get_center_ch(channel, bw_mode, HAL_PRIME_CHNL_OFFSET_LOWER); -+ ChnlWidth = 1; -+ } else { -+ center_freq = 0; -+ ChnlWidth = 0; -+ } -+ -+ -+ SET_VHT_OPERATION_ELE_CHL_WIDTH(operation, ChnlWidth); -+ /* center frequency */ -+ SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ1(operation, center_freq);/* Todo: need to set correct center channel */ -+ SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ2(operation, 0); -+ -+ _rtw_memcpy(operation + 3, pvhtpriv->vht_mcs_map, 2); -+ -+ rtw_set_ie(pbuf, EID_VHTOperation, 5, operation, &len); -+ -+ return len; -+} -+ -+u32 rtw_build_vht_op_mode_notify_ie(_adapter *padapter, u8 *pbuf, u8 bw) -+{ -+ /* struct registry_priv *pregistrypriv = &padapter->registrypriv; */ -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; -+ u32 len = 0; -+ u8 opmode = 0; -+ u8 chnl_width, rx_nss; -+ -+ chnl_width = bw; -+ rx_nss = rtw_vht_mcsmap_to_nss(pvhtpriv->vht_mcs_map); -+ -+ SET_VHT_OPERATING_MODE_FIELD_CHNL_WIDTH(&opmode, chnl_width); -+ SET_VHT_OPERATING_MODE_FIELD_RX_NSS(&opmode, (rx_nss - 1)); -+ SET_VHT_OPERATING_MODE_FIELD_RX_NSS_TYPE(&opmode, 0); /* Todo */ -+ -+ pvhtpriv->vht_op_mode_notify = opmode; -+ -+ pbuf = rtw_set_ie(pbuf, EID_OpModeNotification, 1, &opmode, &len); -+ -+ return len; -+} -+ -+u32 rtw_build_vht_cap_ie(_adapter *padapter, u8 *pbuf) -+{ -+ u8 bw, rf_num, rx_stbc_nss = 0; -+ u16 HighestRate; -+ u8 *pcap, *pcap_mcs; -+ u32 len = 0; -+ u32 rx_packet_offset, max_recvbuf_sz; -+ struct registry_priv *pregistrypriv = &padapter->registrypriv; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ pcap = pvhtpriv->vht_cap; -+ _rtw_memset(pcap, 0, 32); -+ -+ /* B0 B1 Maximum MPDU Length */ -+ rtw_hal_get_def_var(padapter, HAL_DEF_RX_PACKET_OFFSET, &rx_packet_offset); -+ rtw_hal_get_def_var(padapter, HAL_DEF_MAX_RECVBUF_SZ, &max_recvbuf_sz); -+ -+ RTW_DBG("%s, line%d, Available RX buf size = %d bytes\n", __FUNCTION__, __LINE__, max_recvbuf_sz - rx_packet_offset); -+ -+ if ((max_recvbuf_sz - rx_packet_offset) >= 11454) { -+ SET_VHT_CAPABILITY_ELE_MAX_MPDU_LENGTH(pcap, 2); -+ RTW_INFO("%s, line%d, Set MAX MPDU len = 11454 bytes\n", __FUNCTION__, __LINE__); -+ } else if ((max_recvbuf_sz - rx_packet_offset) >= 7991) { -+ SET_VHT_CAPABILITY_ELE_MAX_MPDU_LENGTH(pcap, 1); -+ RTW_INFO("%s, line%d, Set MAX MPDU len = 7991 bytes\n", __FUNCTION__, __LINE__); -+ } else if ((max_recvbuf_sz - rx_packet_offset) >= 3895) { -+ SET_VHT_CAPABILITY_ELE_MAX_MPDU_LENGTH(pcap, 0); -+ RTW_INFO("%s, line%d, Set MAX MPDU len = 3895 bytes\n", __FUNCTION__, __LINE__); -+ } else -+ RTW_ERR("%s, line%d, Error!! Available RX buf size < 3895 bytes\n", __FUNCTION__, __LINE__); -+ -+ /* B2 B3 Supported Channel Width Set */ -+ if (hal_chk_bw_cap(padapter, BW_CAP_160M) && REGSTY_IS_BW_5G_SUPPORT(pregistrypriv, CHANNEL_WIDTH_160)) { -+ if (hal_chk_bw_cap(padapter, BW_CAP_80_80M) && REGSTY_IS_BW_5G_SUPPORT(pregistrypriv, CHANNEL_WIDTH_80_80)) -+ SET_VHT_CAPABILITY_ELE_CHL_WIDTH(pcap, 2); -+ else -+ SET_VHT_CAPABILITY_ELE_CHL_WIDTH(pcap, 1); -+ } else -+ SET_VHT_CAPABILITY_ELE_CHL_WIDTH(pcap, 0); -+ -+ /* B4 Rx LDPC */ -+ if (TEST_FLAG(pvhtpriv->ldpc_cap, LDPC_VHT_ENABLE_RX)) { -+ SET_VHT_CAPABILITY_ELE_RX_LDPC(pcap, 1); -+ RTW_INFO("[VHT] Declare supporting RX LDPC\n"); -+ } -+ -+ /* B5 ShortGI for 80MHz */ -+ SET_VHT_CAPABILITY_ELE_SHORT_GI80M(pcap, pvhtpriv->sgi_80m ? 1 : 0); /* We can receive Short GI of 80M */ -+ if (pvhtpriv->sgi_80m) -+ RTW_INFO("[VHT] Declare supporting SGI 80MHz\n"); -+ -+ /* B6 ShortGI for 160MHz */ -+ /* SET_VHT_CAPABILITY_ELE_SHORT_GI160M(pcap, pvhtpriv->sgi_80m? 1 : 0); */ -+ -+ /* B7 Tx STBC */ -+ if (TEST_FLAG(pvhtpriv->stbc_cap, STBC_VHT_ENABLE_TX)) { -+ SET_VHT_CAPABILITY_ELE_TX_STBC(pcap, 1); -+ RTW_INFO("[VHT] Declare supporting TX STBC\n"); -+ } -+ -+ /* B8 B9 B10 Rx STBC */ -+ if (TEST_FLAG(pvhtpriv->stbc_cap, STBC_VHT_ENABLE_RX)) { -+ rtw_hal_get_def_var(padapter, HAL_DEF_RX_STBC, (u8 *)(&rx_stbc_nss)); -+ -+ SET_VHT_CAPABILITY_ELE_RX_STBC(pcap, rx_stbc_nss); -+ RTW_INFO("[VHT] Declare supporting RX STBC = %d\n", rx_stbc_nss); -+ } -+ #ifdef CONFIG_BEAMFORMING -+ /* B11 SU Beamformer Capable */ -+ if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE)) { -+ SET_VHT_CAPABILITY_ELE_SU_BFER(pcap, 1); -+ RTW_INFO("[VHT] Declare supporting SU Bfer\n"); -+ /* B16 17 18 Number of Sounding Dimensions */ -+ rtw_hal_get_def_var(padapter, HAL_DEF_BEAMFORMER_CAP, (u8 *)&rf_num); -+ SET_VHT_CAPABILITY_ELE_SOUNDING_DIMENSIONS(pcap, rf_num); -+ /* B19 MU Beamformer Capable */ -+ if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE)) { -+ SET_VHT_CAPABILITY_ELE_MU_BFER(pcap, 1); -+ RTW_INFO("[VHT] Declare supporting MU Bfer\n"); -+ } -+ } -+ -+ /* B12 SU Beamformee Capable */ -+ if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE)) { -+ SET_VHT_CAPABILITY_ELE_SU_BFEE(pcap, 1); -+ RTW_INFO("[VHT] Declare supporting SU Bfee\n"); -+ -+ rtw_hal_get_def_var(padapter, HAL_DEF_BEAMFORMEE_CAP, (u8 *)&rf_num); -+ -+ /* IOT action suggested by Yu Chen 2017/3/3 */ -+#ifdef CONFIG_80211AC_VHT -+ if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_BROADCOM) && -+ !pvhtpriv->ap_is_mu_bfer) -+ rf_num = (rf_num >= 2 ? 2 : rf_num); -+#endif -+ /* B13 14 15 Compressed Steering Number of Beamformer Antennas Supported */ -+ SET_VHT_CAPABILITY_ELE_BFER_ANT_SUPP(pcap, rf_num); -+ /* B20 SU Beamformee Capable */ -+ if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE)) { -+ SET_VHT_CAPABILITY_ELE_MU_BFEE(pcap, 1); -+ RTW_INFO("[VHT] Declare supporting MU Bfee\n"); -+ } -+ } -+ #endif/*CONFIG_BEAMFORMING*/ -+ -+ /* B21 VHT TXOP PS */ -+ SET_VHT_CAPABILITY_ELE_TXOP_PS(pcap, 0); -+ /* B22 +HTC-VHT Capable */ -+ SET_VHT_CAPABILITY_ELE_HTC_VHT(pcap, 1); -+ /* B23 24 25 Maximum A-MPDU Length Exponent */ -+ if (pregistrypriv->ampdu_factor != 0xFE) -+ SET_VHT_CAPABILITY_ELE_MAX_RXAMPDU_FACTOR(pcap, pregistrypriv->ampdu_factor); -+ else -+ SET_VHT_CAPABILITY_ELE_MAX_RXAMPDU_FACTOR(pcap, 7); -+ /* B26 27 VHT Link Adaptation Capable */ -+ SET_VHT_CAPABILITY_ELE_LINK_ADAPTION(pcap, 0); -+ -+ pcap_mcs = GET_VHT_CAPABILITY_ELE_RX_MCS(pcap); -+ _rtw_memcpy(pcap_mcs, pvhtpriv->vht_mcs_map, 2); -+ -+ pcap_mcs = GET_VHT_CAPABILITY_ELE_TX_MCS(pcap); -+ _rtw_memcpy(pcap_mcs, pvhtpriv->vht_mcs_map, 2); -+ -+ /* find the largest bw supported by both registry and hal */ -+ bw = hal_largest_bw(padapter, REGSTY_BW_5G(pregistrypriv)); -+ -+ HighestRate = VHT_MCS_DATA_RATE[bw][pvhtpriv->sgi_80m][((pvhtpriv->vht_highest_rate - MGN_VHT1SS_MCS0) & 0x3f)]; -+ HighestRate = (HighestRate + 1) >> 1; -+ -+ SET_VHT_CAPABILITY_ELE_MCS_RX_HIGHEST_RATE(pcap, HighestRate); /* indicate we support highest rx rate is 600Mbps. */ -+ SET_VHT_CAPABILITY_ELE_MCS_TX_HIGHEST_RATE(pcap, HighestRate); /* indicate we support highest tx rate is 600Mbps. */ -+ -+ pbuf = rtw_set_ie(pbuf, EID_VHTCapability, 12, pcap, &len); -+ -+ return len; -+} -+ -+u32 rtw_restructure_vht_ie(_adapter *padapter, u8 *in_ie, u8 *out_ie, uint in_len, uint *pout_len) -+{ -+ struct rf_ctl_t *rfctl = adapter_to_rfctl(padapter); -+ RT_CHANNEL_INFO *chset = rfctl->channel_set; -+ u32 ielen; -+ u8 max_bw; -+ u8 oper_ch, oper_bw = CHANNEL_WIDTH_20, oper_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; -+ u8 *out_vht_op_ie, *ht_op_ie, *vht_cap_ie, *vht_op_ie; -+ struct registry_priv *pregistrypriv = &padapter->registrypriv; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; -+ -+ rtw_vht_use_default_setting(padapter); -+ -+ ht_op_ie = rtw_get_ie(in_ie + 12, WLAN_EID_HT_OPERATION, &ielen, in_len - 12); -+ if (!ht_op_ie || ielen != HT_OP_IE_LEN) -+ goto exit; -+ vht_cap_ie = rtw_get_ie(in_ie + 12, EID_VHTCapability, &ielen, in_len - 12); -+ if (!vht_cap_ie || ielen != VHT_CAP_IE_LEN) -+ goto exit; -+ vht_op_ie = rtw_get_ie(in_ie + 12, EID_VHTOperation, &ielen, in_len - 12); -+ if (!vht_op_ie || ielen != VHT_OP_IE_LEN) -+ goto exit; -+ -+ /* VHT Capabilities element */ -+ *pout_len += rtw_build_vht_cap_ie(padapter, out_ie + *pout_len); -+ -+ -+ /* VHT Operation element */ -+ out_vht_op_ie = out_ie + *pout_len; -+ rtw_set_ie(out_vht_op_ie, EID_VHTOperation, VHT_OP_IE_LEN, vht_op_ie + 2 , pout_len); -+ -+ /* get primary channel from HT_OP_IE */ -+ oper_ch = GET_HT_OP_ELE_PRI_CHL(ht_op_ie + 2); -+ -+ /* find the largest bw supported by both registry and hal */ -+ max_bw = hal_largest_bw(padapter, REGSTY_BW_5G(pregistrypriv)); -+ -+ if (max_bw >= CHANNEL_WIDTH_40) { -+ /* get bw offset form HT_OP_IE */ -+ if (GET_HT_OP_ELE_STA_CHL_WIDTH(ht_op_ie + 2)) { -+ switch (GET_HT_OP_ELE_2ND_CHL_OFFSET(ht_op_ie + 2)) { -+ case SCA: -+ oper_bw = CHANNEL_WIDTH_40; -+ oper_offset = HAL_PRIME_CHNL_OFFSET_LOWER; -+ break; -+ case SCB: -+ oper_bw = CHANNEL_WIDTH_40; -+ oper_offset = HAL_PRIME_CHNL_OFFSET_UPPER; -+ break; -+ } -+ } -+ -+ if (oper_bw == CHANNEL_WIDTH_40) { -+ switch (GET_VHT_OPERATION_ELE_CHL_WIDTH(vht_op_ie + 2)) { -+ case 1: /* 80MHz */ -+ case 2: /* 160MHz */ -+ case 3: /* 80+80 */ -+ oper_bw = CHANNEL_WIDTH_80; /* only support up to 80MHz for now */ -+ break; -+ } -+ -+ oper_bw = rtw_min(oper_bw, max_bw); -+ -+ /* try downgrage bw to fit in channel plan setting */ -+ while (!rtw_chset_is_chbw_valid(chset, oper_ch, oper_bw, oper_offset) -+ || (IS_DFS_SLAVE_WITH_RD(rfctl) -+ && !rtw_odm_dfs_domain_unknown(rfctl_to_dvobj(rfctl)) -+ && rtw_chset_is_chbw_non_ocp(chset, oper_ch, oper_bw, oper_offset)) -+ ) { -+ oper_bw--; -+ if (oper_bw == CHANNEL_WIDTH_20) { -+ oper_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; -+ break; -+ } -+ } -+ } -+ } -+ -+ rtw_warn_on(!rtw_chset_is_chbw_valid(chset, oper_ch, oper_bw, oper_offset)); -+ if (IS_DFS_SLAVE_WITH_RD(rfctl) && !rtw_odm_dfs_domain_unknown(rfctl_to_dvobj(rfctl))) -+ rtw_warn_on(rtw_chset_is_chbw_non_ocp(chset, oper_ch, oper_bw, oper_offset)); -+ -+ /* update VHT_OP_IE */ -+ if (oper_bw < CHANNEL_WIDTH_80) { -+ SET_VHT_OPERATION_ELE_CHL_WIDTH(out_vht_op_ie + 2, 0); -+ SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ1(out_vht_op_ie + 2, 0); -+ SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ2(out_vht_op_ie + 2, 0); -+ } else if (oper_bw == CHANNEL_WIDTH_80) { -+ u8 cch = rtw_get_center_ch(oper_ch, oper_bw, oper_offset); -+ -+ SET_VHT_OPERATION_ELE_CHL_WIDTH(out_vht_op_ie + 2, 1); -+ SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ1(out_vht_op_ie + 2, cch); -+ SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ2(out_vht_op_ie + 2, 0); -+ } else { -+ RTW_ERR(FUNC_ADPT_FMT" unsupported BW:%u\n", FUNC_ADPT_ARG(padapter), oper_bw); -+ rtw_warn_on(1); -+ } -+ -+ /* Operating Mode Notification element */ -+ *pout_len += rtw_build_vht_op_mode_notify_ie(padapter, out_ie + *pout_len, oper_bw); -+ -+ pvhtpriv->vht_option = _TRUE; -+ -+exit: -+ return pvhtpriv->vht_option; -+ -+} -+ -+void VHTOnAssocRsp(_adapter *padapter) -+{ -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ u8 ht_AMPDU_len; -+ -+ RTW_INFO("%s\n", __FUNCTION__); -+ -+ if (!pmlmeinfo->HT_enable) -+ return; -+ -+ if (!pmlmeinfo->VHT_enable) -+ return; -+ -+ ht_AMPDU_len = pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x03; -+ -+ if (pvhtpriv->ampdu_len > ht_AMPDU_len) -+ rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&pvhtpriv->ampdu_len)); -+ -+ rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_MAX_TIME, (u8 *)(&pvhtpriv->vht_highest_rate)); -+} -+ -+void rtw_vht_ies_attach(_adapter *padapter, WLAN_BSSID_EX *pnetwork) -+{ -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ u8 cap_len, operation_len; -+ uint len = 0; -+ sint ie_len = 0; -+ u8 *p = NULL; -+ -+ p = rtw_get_ie(pnetwork->IEs + _BEACON_IE_OFFSET_, EID_VHTCapability, &ie_len, -+ (pnetwork->IELength - _BEACON_IE_OFFSET_)); -+ if (p && ie_len > 0) -+ return; -+ -+ rtw_vht_use_default_setting(padapter); -+ -+ /* VHT Operation mode notifiy bit in Extended IE (127) */ -+ SET_EXT_CAPABILITY_ELE_OP_MODE_NOTIF(pmlmepriv->ext_capab_ie_data, 1); -+ pmlmepriv->ext_capab_ie_len = 10; -+ rtw_set_ie(pnetwork->IEs + pnetwork->IELength, EID_EXTCapability, 8, pmlmepriv->ext_capab_ie_data, &len); -+ pnetwork->IELength += pmlmepriv->ext_capab_ie_len; -+ -+ /* VHT Capabilities element */ -+ cap_len = rtw_build_vht_cap_ie(padapter, pnetwork->IEs + pnetwork->IELength); -+ pnetwork->IELength += cap_len; -+ -+ /* VHT Operation element */ -+ operation_len = rtw_build_vht_operation_ie(padapter, pnetwork->IEs + pnetwork->IELength, -+ pnetwork->Configuration.DSConfig); -+ pnetwork->IELength += operation_len; -+ -+ rtw_check_for_vht20(padapter, pnetwork->IEs + _BEACON_IE_OFFSET_, pnetwork->IELength - _BEACON_IE_OFFSET_); -+ -+ pmlmepriv->vhtpriv.vht_option = _TRUE; -+} -+ -+void rtw_vht_ies_detach(_adapter *padapter, WLAN_BSSID_EX *pnetwork) -+{ -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ -+ rtw_remove_bcn_ie(padapter, pnetwork, EID_EXTCapability); -+ rtw_remove_bcn_ie(padapter, pnetwork, EID_VHTCapability); -+ rtw_remove_bcn_ie(padapter, pnetwork, EID_VHTOperation); -+ -+ pmlmepriv->vhtpriv.vht_option = _FALSE; -+} -+ -+void rtw_check_for_vht20(_adapter *adapter, u8 *ies, int ies_len) -+{ -+ u8 ht_ch, ht_bw, ht_offset; -+ u8 vht_ch, vht_bw, vht_offset; -+ -+ rtw_ies_get_chbw(ies, ies_len, &ht_ch, &ht_bw, &ht_offset, 1, 0); -+ rtw_ies_get_chbw(ies, ies_len, &vht_ch, &vht_bw, &vht_offset, 1, 1); -+ -+ if (ht_bw == CHANNEL_WIDTH_20 && vht_bw >= CHANNEL_WIDTH_80) { -+ u8 *vht_op_ie; -+ int vht_op_ielen; -+ -+ RTW_INFO(FUNC_ADPT_FMT" vht80 is not allowed without ht40\n", FUNC_ADPT_ARG(adapter)); -+ vht_op_ie = rtw_get_ie(ies, EID_VHTOperation, &vht_op_ielen, ies_len); -+ if (vht_op_ie && vht_op_ielen) { -+ RTW_INFO(FUNC_ADPT_FMT" switch to vht20\n", FUNC_ADPT_ARG(adapter)); -+ SET_VHT_OPERATION_ELE_CHL_WIDTH(vht_op_ie + 2, 0); -+ SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ1(vht_op_ie + 2, 0); -+ SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ2(vht_op_ie + 2, 0); -+ } -+ } -+} -+#endif /* CONFIG_80211AC_VHT */ -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_wapi.c linux-5.8/3rdparty/rtl8812au/core/rtw_wapi.c -new file mode 100644 -index 000000000..1c4279f02 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_wapi.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_wapi.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_wapi.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_wapi.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_wapi.c 2021-03-07 18:16:17.027954777 +0200 @@ -0,0 +1,1312 @@ +/****************************************************************************** + * @@ -109005,11 +104889,9 @@ index 000000000..1c4279f02 + } +} +#endif -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_wapi_sms4.c linux-5.8/3rdparty/rtl8812au/core/rtw_wapi_sms4.c -new file mode 100644 -index 000000000..4b7cf957c ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_wapi_sms4.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_wapi_sms4.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_wapi_sms4.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_wapi_sms4.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_wapi_sms4.c 2021-03-07 18:16:17.027954777 +0200 @@ -0,0 +1,922 @@ +/****************************************************************************** + * @@ -109933,12 +105815,1149 @@ index 000000000..4b7cf957c +#endif + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_wlan_util.c linux-5.8/3rdparty/rtl8812au/core/rtw_wlan_util.c -new file mode 100644 -index 000000000..b4cecd116 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_wlan_util.c -@@ -0,0 +1,4971 @@ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_vht.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_vht.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_vht.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_vht.c 2021-03-07 18:16:17.027954777 +0200 +@@ -0,0 +1,1135 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++#define _RTW_VHT_C ++ ++#include ++#include ++ ++#ifdef CONFIG_80211AC_VHT ++const u16 _vht_max_mpdu_len[] = { ++ 3895, ++ 7991, ++ 11454, ++ 0, ++}; ++ ++const u8 _vht_sup_ch_width_set_to_bw_cap[] = { ++ BW_CAP_80M, ++ BW_CAP_80M | BW_CAP_160M, ++ BW_CAP_80M | BW_CAP_160M | BW_CAP_80_80M, ++ 0, ++}; ++ ++const char *const _vht_sup_ch_width_set_str[] = { ++ "80MHz", ++ "160MHz", ++ "160MHz & 80+80MHz", ++ "BW-RSVD", ++}; ++ ++void dump_vht_cap_ie_content(void *sel, const u8 *buf, u32 buf_len) ++{ ++ if (buf_len != VHT_CAP_IE_LEN) { ++ RTW_PRINT_SEL(sel, "Invalid VHT capability IE len:%d != %d\n", buf_len, VHT_CAP_IE_LEN); ++ return; ++ } ++ ++ RTW_PRINT_SEL(sel, "cap_info:%02x %02x %02x %02x: MAX_MPDU_LEN:%u %s%s%s%s%s RX-STBC:%u MAX_AMPDU_LEN:%u\n" ++ , *(buf), *(buf + 1), *(buf + 2), *(buf + 3) ++ , vht_max_mpdu_len(GET_VHT_CAPABILITY_ELE_MAX_MPDU_LENGTH(buf)) ++ , vht_sup_ch_width_set_str(GET_VHT_CAPABILITY_ELE_CHL_WIDTH(buf)) ++ , GET_VHT_CAPABILITY_ELE_RX_LDPC(buf) ? " RX-LDPC" : "" ++ , GET_VHT_CAPABILITY_ELE_SHORT_GI80M(buf) ? " SGI-80" : "" ++ , GET_VHT_CAPABILITY_ELE_SHORT_GI160M(buf) ? " SGI-160" : "" ++ , GET_VHT_CAPABILITY_ELE_TX_STBC(buf) ? " TX-STBC" : "" ++ , GET_VHT_CAPABILITY_ELE_RX_STBC(buf) ++ , VHT_MAX_AMPDU_LEN(GET_VHT_CAPABILITY_ELE_MAX_RXAMPDU_FACTOR(buf)) ++ ); ++} ++ ++void dump_vht_cap_ie(void *sel, const u8 *ie, u32 ie_len) ++{ ++ const u8 *vht_cap_ie; ++ sint vht_cap_ielen; ++ ++ vht_cap_ie = rtw_get_ie(ie, WLAN_EID_VHT_CAPABILITY, &vht_cap_ielen, ie_len); ++ if (!ie || vht_cap_ie != ie) ++ return; ++ ++ dump_vht_cap_ie_content(sel, vht_cap_ie + 2, vht_cap_ielen); ++} ++ ++const char *const _vht_op_ch_width_str[] = { ++ "20 or 40MHz", ++ "80MHz", ++ "160MHz", ++ "80+80MHz", ++ "BW-RSVD", ++}; ++ ++void dump_vht_op_ie_content(void *sel, const u8 *buf, u32 buf_len) ++{ ++ if (buf_len != VHT_OP_IE_LEN) { ++ RTW_PRINT_SEL(sel, "Invalid VHT operation IE len:%d != %d\n", buf_len, VHT_OP_IE_LEN); ++ return; ++ } ++ ++ RTW_PRINT_SEL(sel, "%s, ch0:%u, ch1:%u\n" ++ , vht_op_ch_width_str(GET_VHT_OPERATION_ELE_CHL_WIDTH(buf)) ++ , GET_VHT_OPERATION_ELE_CENTER_FREQ1(buf) ++ , GET_VHT_OPERATION_ELE_CENTER_FREQ2(buf) ++ ); ++} ++ ++void dump_vht_op_ie(void *sel, const u8 *ie, u32 ie_len) ++{ ++ const u8 *vht_op_ie; ++ sint vht_op_ielen; ++ ++ vht_op_ie = rtw_get_ie(ie, WLAN_EID_VHT_OPERATION, &vht_op_ielen, ie_len); ++ if (!ie || vht_op_ie != ie) ++ return; ++ ++ dump_vht_op_ie_content(sel, vht_op_ie + 2, vht_op_ielen); ++} ++ ++/* 20/40/80, ShortGI, MCS Rate */ ++const u16 VHT_MCS_DATA_RATE[3][2][30] = { ++ { { ++ 13, 26, 39, 52, 78, 104, 117, 130, 156, 156, ++ 26, 52, 78, 104, 156, 208, 234, 260, 312, 312, ++ 39, 78, 117, 156, 234, 312, 351, 390, 468, 520 ++ }, /* Long GI, 20MHz */ ++ { ++ 14, 29, 43, 58, 87, 116, 130, 144, 173, 173, ++ 29, 58, 87, 116, 173, 231, 260, 289, 347, 347, ++ 43, 87, 130, 173, 260, 347, 390, 433, 520, 578 ++ } ++ }, /* Short GI, 20MHz */ ++ { { ++ 27, 54, 81, 108, 162, 216, 243, 270, 324, 360, ++ 54, 108, 162, 216, 324, 432, 486, 540, 648, 720, ++ 81, 162, 243, 324, 486, 648, 729, 810, 972, 1080 ++ }, /* Long GI, 40MHz */ ++ { ++ 30, 60, 90, 120, 180, 240, 270, 300, 360, 400, ++ 60, 120, 180, 240, 360, 480, 540, 600, 720, 800, ++ 90, 180, 270, 360, 540, 720, 810, 900, 1080, 1200 ++ } ++ }, /* Short GI, 40MHz */ ++ { { ++ 59, 117, 176, 234, 351, 468, 527, 585, 702, 780, ++ 117, 234, 351, 468, 702, 936, 1053, 1170, 1404, 1560, ++ 176, 351, 527, 702, 1053, 1404, 1580, 1755, 2106, 2340 ++ }, /* Long GI, 80MHz */ ++ { ++ 65, 130, 195, 260, 390, 520, 585, 650, 780, 867, ++ 130, 260, 390, 520, 780, 1040, 1170, 1300, 1560, 1734, ++ 195, 390, 585, 780, 1170, 1560, 1755, 1950, 2340, 2600 ++ } ++ } /* Short GI, 80MHz */ ++}; ++ ++u8 rtw_get_vht_highest_rate(u8 *pvht_mcs_map) ++{ ++ u8 i, j; ++ u8 bit_map; ++ u8 vht_mcs_rate = 0; ++ ++ for (i = 0; i < 2; i++) { ++ if (pvht_mcs_map[i] != 0xff) { ++ for (j = 0; j < 8; j += 2) { ++ bit_map = (pvht_mcs_map[i] >> j) & 3; ++ ++ if (bit_map != 3) ++ vht_mcs_rate = MGN_VHT1SS_MCS7 + 10 * j / 2 + i * 40 + bit_map; /* VHT rate indications begin from 0x90 */ ++ } ++ } ++ } ++ ++ /* RTW_INFO("HighestVHTMCSRate is %x\n", vht_mcs_rate); */ ++ return vht_mcs_rate; ++} ++ ++u8 rtw_vht_mcsmap_to_nss(u8 *pvht_mcs_map) ++{ ++ u8 i, j; ++ u8 bit_map; ++ u8 nss = 0; ++ ++ for (i = 0; i < 2; i++) { ++ if (pvht_mcs_map[i] != 0xff) { ++ for (j = 0; j < 8; j += 2) { ++ bit_map = (pvht_mcs_map[i] >> j) & 3; ++ ++ if (bit_map != 3) ++ nss++; ++ } ++ } ++ } ++ ++ /* RTW_INFO("%s : %dSS\n", __FUNCTION__, nss); */ ++ return nss; ++} ++ ++void rtw_vht_nss_to_mcsmap(u8 nss, u8 *target_mcs_map, u8 *cur_mcs_map) ++{ ++ u8 i, j; ++ u8 cur_rate, target_rate; ++ ++ for (i = 0; i < 2; i++) { ++ target_mcs_map[i] = 0; ++ for (j = 0; j < 8; j += 2) { ++ cur_rate = (cur_mcs_map[i] >> j) & 3; ++ if (cur_rate == 3) /* 0x3 indicates not supported that num of SS */ ++ target_rate = 3; ++ else if (nss <= ((j / 2) + i * 4)) ++ target_rate = 3; ++ else ++ target_rate = cur_rate; ++ ++ target_mcs_map[i] |= (target_rate << j); ++ } ++ } ++ ++ /* RTW_INFO("%s : %dSS\n", __FUNCTION__, nss); */ ++} ++ ++u16 rtw_vht_mcs_to_data_rate(u8 bw, u8 short_GI, u8 vht_mcs_rate) ++{ ++ if (vht_mcs_rate > MGN_VHT3SS_MCS9) ++ vht_mcs_rate = MGN_VHT3SS_MCS9; ++ /* RTW_INFO("bw=%d, short_GI=%d, ((vht_mcs_rate - MGN_VHT1SS_MCS0)&0x3f)=%d\n", bw, short_GI, ((vht_mcs_rate - MGN_VHT1SS_MCS0)&0x3f)); */ ++ return VHT_MCS_DATA_RATE[bw][short_GI][((vht_mcs_rate - MGN_VHT1SS_MCS0) & 0x3f)]; ++} ++ ++void rtw_vht_use_default_setting(_adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ BOOLEAN bHwLDPCSupport = _FALSE, bHwSTBCSupport = _FALSE; ++#ifdef CONFIG_BEAMFORMING ++ BOOLEAN bHwSupportBeamformer = _FALSE, bHwSupportBeamformee = _FALSE; ++ u8 mu_bfer, mu_bfee; ++#endif /* CONFIG_BEAMFORMING */ ++ u8 rf_type = 0; ++ u8 tx_nss, rx_nss; ++ struct hal_spec_t *hal_spec = GET_HAL_SPEC(padapter); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ pvhtpriv->sgi_80m = TEST_FLAG(pregistrypriv->short_gi, BIT2) ? _TRUE : _FALSE; ++ ++ /* LDPC support */ ++ rtw_hal_get_def_var(padapter, HAL_DEF_RX_LDPC, (u8 *)&bHwLDPCSupport); ++ CLEAR_FLAGS(pvhtpriv->ldpc_cap); ++ if (bHwLDPCSupport) { ++ if (TEST_FLAG(pregistrypriv->ldpc_cap, BIT0)) ++ SET_FLAG(pvhtpriv->ldpc_cap, LDPC_VHT_ENABLE_RX); ++ } ++ rtw_hal_get_def_var(padapter, HAL_DEF_TX_LDPC, (u8 *)&bHwLDPCSupport); ++ if (bHwLDPCSupport) { ++ if (TEST_FLAG(pregistrypriv->ldpc_cap, BIT1)) ++ SET_FLAG(pvhtpriv->ldpc_cap, LDPC_VHT_ENABLE_TX); ++ } ++ if (pvhtpriv->ldpc_cap) ++ RTW_INFO("[VHT] Support LDPC = 0x%02X\n", pvhtpriv->ldpc_cap); ++ ++ /* STBC */ ++ rtw_hal_get_def_var(padapter, HAL_DEF_TX_STBC, (u8 *)&bHwSTBCSupport); ++ CLEAR_FLAGS(pvhtpriv->stbc_cap); ++ if (bHwSTBCSupport) { ++ if (TEST_FLAG(pregistrypriv->stbc_cap, BIT1)) ++ SET_FLAG(pvhtpriv->stbc_cap, STBC_VHT_ENABLE_TX); ++ } ++ rtw_hal_get_def_var(padapter, HAL_DEF_RX_STBC, (u8 *)&bHwSTBCSupport); ++ if (bHwSTBCSupport) { ++ if (TEST_FLAG(pregistrypriv->stbc_cap, BIT0)) ++ SET_FLAG(pvhtpriv->stbc_cap, STBC_VHT_ENABLE_RX); ++ } ++ if (pvhtpriv->stbc_cap) ++ RTW_INFO("[VHT] Support STBC = 0x%02X\n", pvhtpriv->stbc_cap); ++ ++ /* Beamforming setting */ ++ CLEAR_FLAGS(pvhtpriv->beamform_cap); ++#ifdef CONFIG_BEAMFORMING ++#ifdef RTW_BEAMFORMING_VERSION_2 ++ /* only enable beamforming in STA client mode */ ++ if (MLME_IS_STA(padapter) && !MLME_IS_GC(padapter) ++ && !MLME_IS_ADHOC(padapter) ++ && !MLME_IS_MESH(padapter)) ++#endif ++ { ++ rtw_hal_get_def_var(padapter, HAL_DEF_EXPLICIT_BEAMFORMER, ++ (u8 *)&bHwSupportBeamformer); ++ rtw_hal_get_def_var(padapter, HAL_DEF_EXPLICIT_BEAMFORMEE, ++ (u8 *)&bHwSupportBeamformee); ++ mu_bfer = _FALSE; ++ mu_bfee = _FALSE; ++ rtw_hal_get_def_var(padapter, HAL_DEF_VHT_MU_BEAMFORMER, &mu_bfer); ++ rtw_hal_get_def_var(padapter, HAL_DEF_VHT_MU_BEAMFORMEE, &mu_bfee); ++ if (TEST_FLAG(pregistrypriv->beamform_cap, BIT0) && bHwSupportBeamformer) { ++#ifdef CONFIG_CONCURRENT_MODE ++ if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) { ++ SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE); ++ RTW_INFO("[VHT] CONCURRENT AP Support Beamformer\n"); ++ if (TEST_FLAG(pregistrypriv->beamform_cap, BIT(2)) ++ && (_TRUE == mu_bfer)) { ++ SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE); ++ RTW_INFO("[VHT] Support MU-MIMO AP\n"); ++ } ++ } else ++ RTW_INFO("[VHT] CONCURRENT not AP ;not allow Support Beamformer\n"); ++#else ++ SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE); ++ RTW_INFO("[VHT] Support Beamformer\n"); ++ if (TEST_FLAG(pregistrypriv->beamform_cap, BIT(2)) ++ && (_TRUE == mu_bfer) ++ && ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) { ++ SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE); ++ RTW_INFO("[VHT] Support MU-MIMO AP\n"); ++ } ++#endif ++ } ++ if (TEST_FLAG(pregistrypriv->beamform_cap, BIT1) && bHwSupportBeamformee) { ++ SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE); ++ RTW_INFO("[VHT] Support Beamformee\n"); ++ if (TEST_FLAG(pregistrypriv->beamform_cap, BIT(3)) ++ && (_TRUE == mu_bfee) ++ && ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE)) { ++ SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE); ++ RTW_INFO("[VHT] Support MU-MIMO STA\n"); ++ } ++ } ++ } ++#endif /* CONFIG_BEAMFORMING */ ++ ++ pvhtpriv->ampdu_len = pregistrypriv->ampdu_factor; ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ tx_nss = rtw_min(rf_type_to_rf_tx_cnt(rf_type), hal_spec->tx_nss_num); ++ rx_nss = rtw_min(rf_type_to_rf_rx_cnt(rf_type), hal_spec->rx_nss_num); ++ ++ /* for now, vhtpriv.vht_mcs_map comes from RX NSS */ ++ rtw_vht_nss_to_mcsmap(rx_nss, pvhtpriv->vht_mcs_map, pregistrypriv->vht_rx_mcs_map); ++ pvhtpriv->vht_highest_rate = rtw_get_vht_highest_rate(pvhtpriv->vht_mcs_map); ++} ++ ++u64 rtw_vht_mcs_map_to_bitmap(u8 *mcs_map, u8 nss) ++{ ++ u8 i, j, tmp; ++ u64 bitmap = 0; ++ u8 bits_nss = nss * 2; ++ ++ for (i = j = 0; i < bits_nss; i += 2, j += 10) { ++ /* every two bits means single sptial stream */ ++ tmp = (mcs_map[i / 8] >> i) & 3; ++ ++ switch (tmp) { ++ case 2: ++ bitmap = bitmap | (0x03ff << j); ++ break; ++ case 1: ++ bitmap = bitmap | (0x01ff << j); ++ break; ++ case 0: ++ bitmap = bitmap | (0x00ff << j); ++ break; ++ default: ++ break; ++ } ++ } ++ ++ RTW_INFO("vht_mcs_map=%02x %02x, nss=%u => bitmap=%016llx\n" ++ , mcs_map[0], mcs_map[1], nss, bitmap); ++ ++ return bitmap; ++} ++ ++#ifdef CONFIG_BEAMFORMING ++void update_sta_vht_info_apmode_bf_cap(_adapter *padapter, struct sta_info *psta) ++{ ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct vht_priv *pvhtpriv_ap = &pmlmepriv->vhtpriv; ++ struct vht_priv *pvhtpriv_sta = &psta->vhtpriv; ++ u16 cur_beamform_cap = 0; ++ ++ /* B11 SU Beamformer Capable, the target supports Beamformer and we are Beamformee */ ++ if (TEST_FLAG(pvhtpriv_ap->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE) && ++ GET_VHT_CAPABILITY_ELE_SU_BFEE(pvhtpriv_sta->vht_cap)) { ++ SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE); ++ /*Shift to BEAMFORMING_VHT_BEAMFORMER_STS_CAP*/ ++ SET_FLAG(cur_beamform_cap, GET_VHT_CAPABILITY_ELE_SU_BFEE_STS_CAP(pvhtpriv_sta->vht_cap) << 8); ++ } ++ ++ /* B12 SU Beamformee Capable, the target supports Beamformee and we are Beamformer */ ++ if (TEST_FLAG(pvhtpriv_ap->beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE) && ++ GET_VHT_CAPABILITY_ELE_SU_BFER(pvhtpriv_sta->vht_cap)) { ++ SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE); ++ /*Shit to BEAMFORMING_VHT_BEAMFORMEE_SOUND_DIM*/ ++ SET_FLAG(cur_beamform_cap, GET_VHT_CAPABILITY_ELE_SU_BFER_SOUND_DIM_NUM(pvhtpriv_sta->vht_cap) << 12); ++ } ++ ++ if (cur_beamform_cap) ++ RTW_INFO("Current STA(%d) VHT Beamforming Setting = %02X\n", psta->cmn.aid, cur_beamform_cap); ++ ++ pvhtpriv_sta->beamform_cap = cur_beamform_cap; ++ psta->cmn.bf_info.vht_beamform_cap = cur_beamform_cap; ++} ++#endif ++ ++void update_sta_vht_info_apmode(_adapter *padapter, PVOID sta) ++{ ++ struct sta_info *psta = (struct sta_info *)sta; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct vht_priv *pvhtpriv_ap = &pmlmepriv->vhtpriv; ++ struct vht_priv *pvhtpriv_sta = &psta->vhtpriv; ++ u8 cur_ldpc_cap = 0, cur_stbc_cap = 0; ++ s8 bw_mode = -1; ++ u8 *pcap_mcs; ++ ++ if (pvhtpriv_sta->vht_option == _FALSE) ++ return; ++ ++ if (pvhtpriv_sta->op_present) { ++ switch (GET_VHT_OPERATION_ELE_CHL_WIDTH(pvhtpriv_sta->vht_op)) { ++ case 1: /* 80MHz */ ++ case 2: /* 160MHz */ ++ case 3: /* 80+80 */ ++ bw_mode = CHANNEL_WIDTH_80; /* only support up to 80MHz for now */ ++ break; ++ } ++ } ++ ++ if (pvhtpriv_sta->notify_present) ++ bw_mode = GET_VHT_OPERATING_MODE_FIELD_CHNL_WIDTH(&pvhtpriv_sta->vht_op_mode_notify); ++ else if (MLME_IS_AP(padapter)) { ++ /* for VHT client without Operating Mode Notify IE; minimal 80MHz */ ++ if (bw_mode < CHANNEL_WIDTH_80) ++ bw_mode = CHANNEL_WIDTH_80; ++ } ++ ++ if (bw_mode != -1) ++ psta->cmn.bw_mode = bw_mode; /* update bw_mode only if get value from VHT IEs */ ++ ++ psta->cmn.ra_info.is_vht_enable = _TRUE; ++ ++ /* B4 Rx LDPC */ ++ if (TEST_FLAG(pvhtpriv_ap->ldpc_cap, LDPC_VHT_ENABLE_TX) && ++ GET_VHT_CAPABILITY_ELE_RX_LDPC(pvhtpriv_sta->vht_cap)) { ++ SET_FLAG(cur_ldpc_cap, (LDPC_VHT_ENABLE_TX | LDPC_VHT_CAP_TX)); ++ RTW_INFO("Current STA(%d) VHT LDPC = %02X\n", psta->cmn.aid, cur_ldpc_cap); ++ } ++ pvhtpriv_sta->ldpc_cap = cur_ldpc_cap; ++ ++ if (psta->cmn.bw_mode > pmlmeext->cur_bwmode) ++ psta->cmn.bw_mode = pmlmeext->cur_bwmode; ++ ++ if (psta->cmn.bw_mode == CHANNEL_WIDTH_80) { ++ /* B5 Short GI for 80 MHz */ ++ pvhtpriv_sta->sgi_80m = (GET_VHT_CAPABILITY_ELE_SHORT_GI80M(pvhtpriv_sta->vht_cap) & pvhtpriv_ap->sgi_80m) ? _TRUE : _FALSE; ++ /* RTW_INFO("Current STA ShortGI80MHz = %d\n", pvhtpriv_sta->sgi_80m); */ ++ } else if (psta->cmn.bw_mode >= CHANNEL_WIDTH_160) { ++ /* B5 Short GI for 80 MHz */ ++ pvhtpriv_sta->sgi_80m = (GET_VHT_CAPABILITY_ELE_SHORT_GI160M(pvhtpriv_sta->vht_cap) & pvhtpriv_ap->sgi_80m) ? _TRUE : _FALSE; ++ /* RTW_INFO("Current STA ShortGI160MHz = %d\n", pvhtpriv_sta->sgi_80m); */ ++ } ++ ++ /* B8 B9 B10 Rx STBC */ ++ if (TEST_FLAG(pvhtpriv_ap->stbc_cap, STBC_VHT_ENABLE_TX) && ++ GET_VHT_CAPABILITY_ELE_RX_STBC(pvhtpriv_sta->vht_cap)) { ++ SET_FLAG(cur_stbc_cap, (STBC_VHT_ENABLE_TX | STBC_VHT_CAP_TX)); ++ RTW_INFO("Current STA(%d) VHT STBC = %02X\n", psta->cmn.aid, cur_stbc_cap); ++ } ++ pvhtpriv_sta->stbc_cap = cur_stbc_cap; ++ ++#ifdef CONFIG_BEAMFORMING ++ update_sta_vht_info_apmode_bf_cap(padapter, psta); ++#endif ++ ++ /* B23 B24 B25 Maximum A-MPDU Length Exponent */ ++ pvhtpriv_sta->ampdu_len = GET_VHT_CAPABILITY_ELE_MAX_RXAMPDU_FACTOR(pvhtpriv_sta->vht_cap); ++ ++ pcap_mcs = GET_VHT_CAPABILITY_ELE_RX_MCS(pvhtpriv_sta->vht_cap); ++ _rtw_memcpy(pvhtpriv_sta->vht_mcs_map, pcap_mcs, 2); ++ pvhtpriv_sta->vht_highest_rate = rtw_get_vht_highest_rate(pvhtpriv_sta->vht_mcs_map); ++} ++ ++void update_hw_vht_param(_adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u8 ht_AMPDU_len; ++ ++ ht_AMPDU_len = pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x03; ++ ++ if (pvhtpriv->ampdu_len > ht_AMPDU_len) ++ rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&pvhtpriv->ampdu_len)); ++} ++ ++#ifdef ROKU_PRIVATE ++u8 VHT_get_ss_from_map(u8 *vht_mcs_map) ++{ ++ u8 i, j; ++ u8 ss = 0; ++ ++ for (i = 0; i < 2; i++) { ++ if (vht_mcs_map[i] != 0xff) { ++ for (j = 0; j < 8; j += 2) { ++ if (((vht_mcs_map[i] >> j) & 0x03) == 0x03) ++ break; ++ ss++; ++ } ++ } ++ ++ } ++ ++return ss; ++} ++ ++void VHT_caps_handler_infra_ap(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct vht_priv_infra_ap *pvhtpriv = &pmlmepriv->vhtpriv_infra_ap; ++ u8 cur_stbc_cap_infra_ap = 0; ++ u16 cur_beamform_cap_infra_ap = 0; ++ u8 *pcap_mcs; ++ u8 *pcap_mcs_tx; ++ u8 Rx_ss = 0, Tx_ss = 0; ++ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ if (pIE == NULL) ++ return; ++ ++ pmlmeinfo->ht_vht_received |= BIT(1); ++ ++ pvhtpriv->ldpc_cap_infra_ap = GET_VHT_CAPABILITY_ELE_RX_LDPC(pIE->data); ++ ++ if (GET_VHT_CAPABILITY_ELE_RX_STBC(pIE->data)) ++ SET_FLAG(cur_stbc_cap_infra_ap, STBC_VHT_ENABLE_RX); ++ if (GET_VHT_CAPABILITY_ELE_TX_STBC(pIE->data)) ++ SET_FLAG(cur_stbc_cap_infra_ap, STBC_VHT_ENABLE_TX); ++ pvhtpriv->stbc_cap_infra_ap = cur_stbc_cap_infra_ap; ++ ++ /*store ap info for channel bandwidth*/ ++ pvhtpriv->channel_width_infra_ap = GET_VHT_CAPABILITY_ELE_CHL_WIDTH(pIE->data); ++ ++ /*check B11: SU Beamformer Capable and B12: SU Beamformee B19: MU Beamformer B20:MU Beamformee*/ ++ if (GET_VHT_CAPABILITY_ELE_SU_BFER(pIE->data)) ++ SET_FLAG(cur_beamform_cap_infra_ap, BEAMFORMING_VHT_BEAMFORMER_ENABLE); ++ if (GET_VHT_CAPABILITY_ELE_SU_BFEE(pIE->data)) ++ SET_FLAG(cur_beamform_cap_infra_ap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE); ++ if (GET_VHT_CAPABILITY_ELE_MU_BFER(pIE->data)) ++ SET_FLAG(cur_beamform_cap_infra_ap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE); ++ if (GET_VHT_CAPABILITY_ELE_MU_BFEE(pIE->data)) ++ SET_FLAG(cur_beamform_cap_infra_ap, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE); ++ pvhtpriv->beamform_cap_infra_ap = cur_beamform_cap_infra_ap; ++ ++ /*store information about vht_mcs_set*/ ++ pcap_mcs = GET_VHT_CAPABILITY_ELE_RX_MCS(pIE->data); ++ pcap_mcs_tx = GET_VHT_CAPABILITY_ELE_TX_MCS(pIE->data); ++ _rtw_memcpy(pvhtpriv->vht_mcs_map_infra_ap, pcap_mcs, 2); ++ _rtw_memcpy(pvhtpriv->vht_mcs_map_tx_infra_ap, pcap_mcs_tx, 2); ++ ++ Rx_ss = VHT_get_ss_from_map(pvhtpriv->vht_mcs_map_infra_ap); ++ Tx_ss = VHT_get_ss_from_map(pvhtpriv->vht_mcs_map_tx_infra_ap); ++ if (Rx_ss >= Tx_ss) { ++ pvhtpriv->number_of_streams_infra_ap = Rx_ss; ++ } else{ ++ pvhtpriv->number_of_streams_infra_ap = Tx_ss; ++ } ++ ++} ++#endif /* ROKU_PRIVATE */ ++ ++void VHT_caps_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE) ++{ ++ struct hal_spec_t *hal_spec = GET_HAL_SPEC(padapter); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u8 cur_ldpc_cap = 0, cur_stbc_cap = 0, rf_type = RF_1T1R, tx_nss = 0; ++ u16 cur_beamform_cap = 0; ++ u8 *pcap_mcs; ++ ++ if (pIE == NULL) ++ return; ++ ++ if (pvhtpriv->vht_option == _FALSE) ++ return; ++ ++ pmlmeinfo->VHT_enable = 1; ++ ++ /* B4 Rx LDPC */ ++ if (TEST_FLAG(pvhtpriv->ldpc_cap, LDPC_VHT_ENABLE_TX) && ++ GET_VHT_CAPABILITY_ELE_RX_LDPC(pIE->data)) { ++ SET_FLAG(cur_ldpc_cap, (LDPC_VHT_ENABLE_TX | LDPC_VHT_CAP_TX)); ++ RTW_INFO("Current VHT LDPC Setting = %02X\n", cur_ldpc_cap); ++ } ++ pvhtpriv->ldpc_cap = cur_ldpc_cap; ++ ++ /* B5 Short GI for 80 MHz */ ++ pvhtpriv->sgi_80m = (GET_VHT_CAPABILITY_ELE_SHORT_GI80M(pIE->data) & pvhtpriv->sgi_80m) ? _TRUE : _FALSE; ++ /* RTW_INFO("Current ShortGI80MHz = %d\n", pvhtpriv->sgi_80m); */ ++ ++ /* B8 B9 B10 Rx STBC */ ++ if (TEST_FLAG(pvhtpriv->stbc_cap, STBC_VHT_ENABLE_TX) && ++ GET_VHT_CAPABILITY_ELE_RX_STBC(pIE->data)) { ++ SET_FLAG(cur_stbc_cap, (STBC_VHT_ENABLE_TX | STBC_VHT_CAP_TX)); ++ RTW_INFO("Current VHT STBC Setting = %02X\n", cur_stbc_cap); ++ } ++ pvhtpriv->stbc_cap = cur_stbc_cap; ++#ifdef CONFIG_BEAMFORMING ++#ifdef RTW_BEAMFORMING_VERSION_2 ++ /* ++ * B11 SU Beamformer Capable, ++ * the target supports Beamformer and we are Beamformee ++ */ ++ if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE) ++ && GET_VHT_CAPABILITY_ELE_SU_BFER(pIE->data)) { ++ SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE); ++ ++ /* Shift to BEAMFORMING_VHT_BEAMFORMEE_STS_CAP */ ++ SET_FLAG(cur_beamform_cap, GET_VHT_CAPABILITY_ELE_SU_BFEE_STS_CAP(pIE->data) << 8); ++ ++ /* ++ * B19 MU Beamformer Capable, ++ * the target supports Beamformer and we are Beamformee ++ */ ++ if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE) ++ && GET_VHT_CAPABILITY_ELE_MU_BFER(pIE->data)) ++ SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE); ++ } ++ ++ /* ++ * B12 SU Beamformee Capable, ++ * the target supports Beamformee and we are Beamformer ++ */ ++ if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE) ++ && GET_VHT_CAPABILITY_ELE_SU_BFEE(pIE->data)) { ++ SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE); ++ ++ /* Shit to BEAMFORMING_VHT_BEAMFORMER_SOUND_DIM */ ++ SET_FLAG(cur_beamform_cap, GET_VHT_CAPABILITY_ELE_SU_BFER_SOUND_DIM_NUM(pIE->data) << 12); ++ ++ /* ++ * B20 MU Beamformee Capable, ++ * the target supports Beamformee and we are Beamformer ++ */ ++ if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE) ++ && GET_VHT_CAPABILITY_ELE_MU_BFEE(pIE->data)) ++ SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE); ++ } ++ ++ pvhtpriv->beamform_cap = cur_beamform_cap; ++ RTW_INFO("Current VHT Beamforming Setting=0x%04X\n", cur_beamform_cap); ++#else /* !RTW_BEAMFORMING_VERSION_2 */ ++ /* B11 SU Beamformer Capable, the target supports Beamformer and we are Beamformee */ ++ if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE) && ++ GET_VHT_CAPABILITY_ELE_SU_BFEE(pIE->data)) { ++ SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE); ++ /*Shift to BEAMFORMING_VHT_BEAMFORMER_STS_CAP*/ ++ SET_FLAG(cur_beamform_cap, GET_VHT_CAPABILITY_ELE_SU_BFEE_STS_CAP(pIE->data) << 8); ++ } ++ ++ /* B12 SU Beamformee Capable, the target supports Beamformee and we are Beamformer */ ++ if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE) && ++ GET_VHT_CAPABILITY_ELE_SU_BFER(pIE->data)) { ++ SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE); ++ /*Shit to BEAMFORMING_VHT_BEAMFORMEE_SOUND_DIM*/ ++ SET_FLAG(cur_beamform_cap, GET_VHT_CAPABILITY_ELE_SU_BFER_SOUND_DIM_NUM(pIE->data) << 12); ++ ++ } ++ pvhtpriv->beamform_cap = cur_beamform_cap; ++ if (cur_beamform_cap) ++ RTW_INFO("Current VHT Beamforming Setting = %02X\n", cur_beamform_cap); ++#endif /* !RTW_BEAMFORMING_VERSION_2 */ ++#endif /* CONFIG_BEAMFORMING */ ++ /* B23 B24 B25 Maximum A-MPDU Length Exponent */ ++ pvhtpriv->ampdu_len = GET_VHT_CAPABILITY_ELE_MAX_RXAMPDU_FACTOR(pIE->data); ++ ++ pcap_mcs = GET_VHT_CAPABILITY_ELE_RX_MCS(pIE->data); ++ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ tx_nss = rtw_min(rf_type_to_rf_tx_cnt(rf_type), hal_spec->tx_nss_num); ++ rtw_vht_nss_to_mcsmap(tx_nss, pvhtpriv->vht_mcs_map, pcap_mcs); ++ pvhtpriv->vht_highest_rate = rtw_get_vht_highest_rate(pvhtpriv->vht_mcs_map); ++} ++ ++void VHT_operation_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; ++ ++ if (pIE == NULL) ++ return; ++ ++ if (pvhtpriv->vht_option == _FALSE) ++ return; ++} ++ ++void rtw_process_vht_op_mode_notify(_adapter *padapter, u8 *pframe, PVOID sta) ++{ ++ struct sta_info *psta = (struct sta_info *)sta; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; ++ struct registry_priv *regsty = adapter_to_regsty(padapter); ++ u8 target_bw; ++ u8 target_rxss, current_rxss; ++ u8 update_ra = _FALSE; ++ u8 tx_nss = 0, rf_type = RF_1T1R; ++ struct hal_spec_t *hal_spec = GET_HAL_SPEC(padapter); ++ ++ if (pvhtpriv->vht_option == _FALSE) ++ return; ++ ++ target_bw = GET_VHT_OPERATING_MODE_FIELD_CHNL_WIDTH(pframe); ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ tx_nss = rtw_min(rf_type_to_rf_tx_cnt(rf_type), hal_spec->tx_nss_num); ++ target_rxss = rtw_min(tx_nss, (GET_VHT_OPERATING_MODE_FIELD_RX_NSS(pframe) + 1)); ++ ++ if (target_bw != psta->cmn.bw_mode) { ++ if (hal_is_bw_support(padapter, target_bw) ++ && REGSTY_IS_BW_5G_SUPPORT(regsty, target_bw) ++ ) { ++ update_ra = _TRUE; ++ psta->cmn.bw_mode = target_bw; ++ } ++ } ++ ++ current_rxss = rtw_vht_mcsmap_to_nss(psta->vhtpriv.vht_mcs_map); ++ if (target_rxss != current_rxss) { ++ u8 vht_mcs_map[2] = {}; ++ ++ update_ra = _TRUE; ++ ++ rtw_vht_nss_to_mcsmap(target_rxss, vht_mcs_map, psta->vhtpriv.vht_mcs_map); ++ _rtw_memcpy(psta->vhtpriv.vht_mcs_map, vht_mcs_map, 2); ++ ++ rtw_hal_update_sta_ra_info(padapter, psta); ++ } ++ ++ if (update_ra) ++ rtw_dm_ra_mask_wk_cmd(padapter, (u8 *)psta); ++} ++ ++u32 rtw_build_vht_operation_ie(_adapter *padapter, u8 *pbuf, u8 channel) ++{ ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; ++ /* struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; */ ++ u8 ChnlWidth, center_freq, bw_mode; ++ u32 len = 0; ++ u8 operation[5]; ++ ++ _rtw_memset(operation, 0, 5); ++ ++ bw_mode = REGSTY_BW_5G(pregistrypriv); /* TODO: control op bw with other info */ ++ ++ if (hal_chk_bw_cap(padapter, BW_CAP_80M | BW_CAP_160M) ++ && REGSTY_BW_5G(pregistrypriv) >= CHANNEL_WIDTH_80 ++ ) { ++ center_freq = rtw_get_center_ch(channel, bw_mode, HAL_PRIME_CHNL_OFFSET_LOWER); ++ ChnlWidth = 1; ++ } else { ++ center_freq = 0; ++ ChnlWidth = 0; ++ } ++ ++ ++ SET_VHT_OPERATION_ELE_CHL_WIDTH(operation, ChnlWidth); ++ /* center frequency */ ++ SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ1(operation, center_freq);/* Todo: need to set correct center channel */ ++ SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ2(operation, 0); ++ ++ _rtw_memcpy(operation + 3, pvhtpriv->vht_mcs_map, 2); ++ ++ rtw_set_ie(pbuf, EID_VHTOperation, 5, operation, &len); ++ ++ return len; ++} ++ ++u32 rtw_build_vht_op_mode_notify_ie(_adapter *padapter, u8 *pbuf, u8 bw) ++{ ++ /* struct registry_priv *pregistrypriv = &padapter->registrypriv; */ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; ++ u32 len = 0; ++ u8 opmode = 0; ++ u8 chnl_width, rx_nss; ++ ++ chnl_width = bw; ++ rx_nss = rtw_vht_mcsmap_to_nss(pvhtpriv->vht_mcs_map); ++ ++ SET_VHT_OPERATING_MODE_FIELD_CHNL_WIDTH(&opmode, chnl_width); ++ SET_VHT_OPERATING_MODE_FIELD_RX_NSS(&opmode, (rx_nss - 1)); ++ SET_VHT_OPERATING_MODE_FIELD_RX_NSS_TYPE(&opmode, 0); /* Todo */ ++ ++ pvhtpriv->vht_op_mode_notify = opmode; ++ ++ pbuf = rtw_set_ie(pbuf, EID_OpModeNotification, 1, &opmode, &len); ++ ++ return len; ++} ++ ++u32 rtw_build_vht_cap_ie(_adapter *padapter, u8 *pbuf) ++{ ++ u8 bw, rf_num, rx_stbc_nss = 0; ++ u16 HighestRate; ++ u8 *pcap, *pcap_mcs; ++ u32 len = 0; ++ u32 rx_packet_offset, max_recvbuf_sz; ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ pcap = pvhtpriv->vht_cap; ++ _rtw_memset(pcap, 0, 32); ++ ++ /* B0 B1 Maximum MPDU Length */ ++ rtw_hal_get_def_var(padapter, HAL_DEF_RX_PACKET_OFFSET, &rx_packet_offset); ++ rtw_hal_get_def_var(padapter, HAL_DEF_MAX_RECVBUF_SZ, &max_recvbuf_sz); ++ ++ RTW_DBG("%s, line%d, Available RX buf size = %d bytes\n", __FUNCTION__, __LINE__, max_recvbuf_sz - rx_packet_offset); ++ ++ if ((max_recvbuf_sz - rx_packet_offset) >= 11454) { ++ SET_VHT_CAPABILITY_ELE_MAX_MPDU_LENGTH(pcap, 2); ++ RTW_INFO("%s, line%d, Set MAX MPDU len = 11454 bytes\n", __FUNCTION__, __LINE__); ++ } else if ((max_recvbuf_sz - rx_packet_offset) >= 7991) { ++ SET_VHT_CAPABILITY_ELE_MAX_MPDU_LENGTH(pcap, 1); ++ RTW_INFO("%s, line%d, Set MAX MPDU len = 7991 bytes\n", __FUNCTION__, __LINE__); ++ } else if ((max_recvbuf_sz - rx_packet_offset) >= 3895) { ++ SET_VHT_CAPABILITY_ELE_MAX_MPDU_LENGTH(pcap, 0); ++ RTW_INFO("%s, line%d, Set MAX MPDU len = 3895 bytes\n", __FUNCTION__, __LINE__); ++ } else ++ RTW_ERR("%s, line%d, Error!! Available RX buf size < 3895 bytes\n", __FUNCTION__, __LINE__); ++ ++ /* B2 B3 Supported Channel Width Set */ ++ if (hal_chk_bw_cap(padapter, BW_CAP_160M) && REGSTY_IS_BW_5G_SUPPORT(pregistrypriv, CHANNEL_WIDTH_160)) { ++ if (hal_chk_bw_cap(padapter, BW_CAP_80_80M) && REGSTY_IS_BW_5G_SUPPORT(pregistrypriv, CHANNEL_WIDTH_80_80)) ++ SET_VHT_CAPABILITY_ELE_CHL_WIDTH(pcap, 2); ++ else ++ SET_VHT_CAPABILITY_ELE_CHL_WIDTH(pcap, 1); ++ } else ++ SET_VHT_CAPABILITY_ELE_CHL_WIDTH(pcap, 0); ++ ++ /* B4 Rx LDPC */ ++ if (TEST_FLAG(pvhtpriv->ldpc_cap, LDPC_VHT_ENABLE_RX)) { ++ SET_VHT_CAPABILITY_ELE_RX_LDPC(pcap, 1); ++ RTW_INFO("[VHT] Declare supporting RX LDPC\n"); ++ } ++ ++ /* B5 ShortGI for 80MHz */ ++ SET_VHT_CAPABILITY_ELE_SHORT_GI80M(pcap, pvhtpriv->sgi_80m ? 1 : 0); /* We can receive Short GI of 80M */ ++ if (pvhtpriv->sgi_80m) ++ RTW_INFO("[VHT] Declare supporting SGI 80MHz\n"); ++ ++ /* B6 ShortGI for 160MHz */ ++ /* SET_VHT_CAPABILITY_ELE_SHORT_GI160M(pcap, pvhtpriv->sgi_80m? 1 : 0); */ ++ ++ /* B7 Tx STBC */ ++ if (TEST_FLAG(pvhtpriv->stbc_cap, STBC_VHT_ENABLE_TX)) { ++ SET_VHT_CAPABILITY_ELE_TX_STBC(pcap, 1); ++ RTW_INFO("[VHT] Declare supporting TX STBC\n"); ++ } ++ ++ /* B8 B9 B10 Rx STBC */ ++ if (TEST_FLAG(pvhtpriv->stbc_cap, STBC_VHT_ENABLE_RX)) { ++ rtw_hal_get_def_var(padapter, HAL_DEF_RX_STBC, (u8 *)(&rx_stbc_nss)); ++ ++ SET_VHT_CAPABILITY_ELE_RX_STBC(pcap, rx_stbc_nss); ++ RTW_INFO("[VHT] Declare supporting RX STBC = %d\n", rx_stbc_nss); ++ } ++ #ifdef CONFIG_BEAMFORMING ++ /* B11 SU Beamformer Capable */ ++ if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE)) { ++ SET_VHT_CAPABILITY_ELE_SU_BFER(pcap, 1); ++ RTW_INFO("[VHT] Declare supporting SU Bfer\n"); ++ /* B16 17 18 Number of Sounding Dimensions */ ++ rtw_hal_get_def_var(padapter, HAL_DEF_BEAMFORMER_CAP, (u8 *)&rf_num); ++ SET_VHT_CAPABILITY_ELE_SOUNDING_DIMENSIONS(pcap, rf_num); ++ /* B19 MU Beamformer Capable */ ++ if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE)) { ++ SET_VHT_CAPABILITY_ELE_MU_BFER(pcap, 1); ++ RTW_INFO("[VHT] Declare supporting MU Bfer\n"); ++ } ++ } ++ ++ /* B12 SU Beamformee Capable */ ++ if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE)) { ++ SET_VHT_CAPABILITY_ELE_SU_BFEE(pcap, 1); ++ RTW_INFO("[VHT] Declare supporting SU Bfee\n"); ++ ++ rtw_hal_get_def_var(padapter, HAL_DEF_BEAMFORMEE_CAP, (u8 *)&rf_num); ++ ++ /* IOT action suggested by Yu Chen 2017/3/3 */ ++#ifdef CONFIG_80211AC_VHT ++ if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_BROADCOM) && ++ !pvhtpriv->ap_is_mu_bfer) ++ rf_num = (rf_num >= 2 ? 2 : rf_num); ++#endif ++ /* B13 14 15 Compressed Steering Number of Beamformer Antennas Supported */ ++ SET_VHT_CAPABILITY_ELE_BFER_ANT_SUPP(pcap, rf_num); ++ /* B20 SU Beamformee Capable */ ++ if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE)) { ++ SET_VHT_CAPABILITY_ELE_MU_BFEE(pcap, 1); ++ RTW_INFO("[VHT] Declare supporting MU Bfee\n"); ++ } ++ } ++ #endif/*CONFIG_BEAMFORMING*/ ++ ++ /* B21 VHT TXOP PS */ ++ SET_VHT_CAPABILITY_ELE_TXOP_PS(pcap, 0); ++ /* B22 +HTC-VHT Capable */ ++ SET_VHT_CAPABILITY_ELE_HTC_VHT(pcap, 1); ++ /* B23 24 25 Maximum A-MPDU Length Exponent */ ++ if (pregistrypriv->ampdu_factor != 0xFE) ++ SET_VHT_CAPABILITY_ELE_MAX_RXAMPDU_FACTOR(pcap, pregistrypriv->ampdu_factor); ++ else ++ SET_VHT_CAPABILITY_ELE_MAX_RXAMPDU_FACTOR(pcap, 7); ++ /* B26 27 VHT Link Adaptation Capable */ ++ SET_VHT_CAPABILITY_ELE_LINK_ADAPTION(pcap, 0); ++ ++ pcap_mcs = GET_VHT_CAPABILITY_ELE_RX_MCS(pcap); ++ _rtw_memcpy(pcap_mcs, pvhtpriv->vht_mcs_map, 2); ++ ++ pcap_mcs = GET_VHT_CAPABILITY_ELE_TX_MCS(pcap); ++ _rtw_memcpy(pcap_mcs, pvhtpriv->vht_mcs_map, 2); ++ ++ /* find the largest bw supported by both registry and hal */ ++ bw = hal_largest_bw(padapter, REGSTY_BW_5G(pregistrypriv)); ++ ++ HighestRate = VHT_MCS_DATA_RATE[bw][pvhtpriv->sgi_80m][((pvhtpriv->vht_highest_rate - MGN_VHT1SS_MCS0) & 0x3f)]; ++ HighestRate = (HighestRate + 1) >> 1; ++ ++ SET_VHT_CAPABILITY_ELE_MCS_RX_HIGHEST_RATE(pcap, HighestRate); /* indicate we support highest rx rate is 600Mbps. */ ++ SET_VHT_CAPABILITY_ELE_MCS_TX_HIGHEST_RATE(pcap, HighestRate); /* indicate we support highest tx rate is 600Mbps. */ ++ ++ pbuf = rtw_set_ie(pbuf, EID_VHTCapability, 12, pcap, &len); ++ ++ return len; ++} ++ ++u32 rtw_restructure_vht_ie(_adapter *padapter, u8 *in_ie, u8 *out_ie, uint in_len, uint *pout_len) ++{ ++ struct rf_ctl_t *rfctl = adapter_to_rfctl(padapter); ++ RT_CHANNEL_INFO *chset = rfctl->channel_set; ++ u32 ielen; ++ u8 max_bw; ++ u8 oper_ch, oper_bw = CHANNEL_WIDTH_20, oper_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ u8 *out_vht_op_ie, *ht_op_ie, *vht_cap_ie, *vht_op_ie; ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; ++ ++ rtw_vht_use_default_setting(padapter); ++ ++ ht_op_ie = rtw_get_ie(in_ie + 12, WLAN_EID_HT_OPERATION, &ielen, in_len - 12); ++ if (!ht_op_ie || ielen != HT_OP_IE_LEN) ++ goto exit; ++ vht_cap_ie = rtw_get_ie(in_ie + 12, EID_VHTCapability, &ielen, in_len - 12); ++ if (!vht_cap_ie || ielen != VHT_CAP_IE_LEN) ++ goto exit; ++ vht_op_ie = rtw_get_ie(in_ie + 12, EID_VHTOperation, &ielen, in_len - 12); ++ if (!vht_op_ie || ielen != VHT_OP_IE_LEN) ++ goto exit; ++ ++ /* VHT Capabilities element */ ++ *pout_len += rtw_build_vht_cap_ie(padapter, out_ie + *pout_len); ++ ++ ++ /* VHT Operation element */ ++ out_vht_op_ie = out_ie + *pout_len; ++ rtw_set_ie(out_vht_op_ie, EID_VHTOperation, VHT_OP_IE_LEN, vht_op_ie + 2 , pout_len); ++ ++ /* get primary channel from HT_OP_IE */ ++ oper_ch = GET_HT_OP_ELE_PRI_CHL(ht_op_ie + 2); ++ ++ /* find the largest bw supported by both registry and hal */ ++ max_bw = hal_largest_bw(padapter, REGSTY_BW_5G(pregistrypriv)); ++ ++ if (max_bw >= CHANNEL_WIDTH_40) { ++ /* get bw offset form HT_OP_IE */ ++ if (GET_HT_OP_ELE_STA_CHL_WIDTH(ht_op_ie + 2)) { ++ switch (GET_HT_OP_ELE_2ND_CHL_OFFSET(ht_op_ie + 2)) { ++ case SCA: ++ oper_bw = CHANNEL_WIDTH_40; ++ oper_offset = HAL_PRIME_CHNL_OFFSET_LOWER; ++ break; ++ case SCB: ++ oper_bw = CHANNEL_WIDTH_40; ++ oper_offset = HAL_PRIME_CHNL_OFFSET_UPPER; ++ break; ++ } ++ } ++ ++ if (oper_bw == CHANNEL_WIDTH_40) { ++ switch (GET_VHT_OPERATION_ELE_CHL_WIDTH(vht_op_ie + 2)) { ++ case 1: /* 80MHz */ ++ case 2: /* 160MHz */ ++ case 3: /* 80+80 */ ++ oper_bw = CHANNEL_WIDTH_80; /* only support up to 80MHz for now */ ++ break; ++ } ++ ++ oper_bw = rtw_min(oper_bw, max_bw); ++ ++ /* try downgrage bw to fit in channel plan setting */ ++ while (!rtw_chset_is_chbw_valid(chset, oper_ch, oper_bw, oper_offset) ++ || (IS_DFS_SLAVE_WITH_RD(rfctl) ++ && !rtw_odm_dfs_domain_unknown(rfctl_to_dvobj(rfctl)) ++ && rtw_chset_is_chbw_non_ocp(chset, oper_ch, oper_bw, oper_offset)) ++ ) { ++ oper_bw--; ++ if (oper_bw == CHANNEL_WIDTH_20) { ++ oper_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ break; ++ } ++ } ++ } ++ } ++ ++ rtw_warn_on(!rtw_chset_is_chbw_valid(chset, oper_ch, oper_bw, oper_offset)); ++ if (IS_DFS_SLAVE_WITH_RD(rfctl) && !rtw_odm_dfs_domain_unknown(rfctl_to_dvobj(rfctl))) ++ rtw_warn_on(rtw_chset_is_chbw_non_ocp(chset, oper_ch, oper_bw, oper_offset)); ++ ++ /* update VHT_OP_IE */ ++ if (oper_bw < CHANNEL_WIDTH_80) { ++ SET_VHT_OPERATION_ELE_CHL_WIDTH(out_vht_op_ie + 2, 0); ++ SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ1(out_vht_op_ie + 2, 0); ++ SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ2(out_vht_op_ie + 2, 0); ++ } else if (oper_bw == CHANNEL_WIDTH_80) { ++ u8 cch = rtw_get_center_ch(oper_ch, oper_bw, oper_offset); ++ ++ SET_VHT_OPERATION_ELE_CHL_WIDTH(out_vht_op_ie + 2, 1); ++ SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ1(out_vht_op_ie + 2, cch); ++ SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ2(out_vht_op_ie + 2, 0); ++ } else { ++ RTW_ERR(FUNC_ADPT_FMT" unsupported BW:%u\n", FUNC_ADPT_ARG(padapter), oper_bw); ++ rtw_warn_on(1); ++ } ++ ++ /* Operating Mode Notification element */ ++ *pout_len += rtw_build_vht_op_mode_notify_ie(padapter, out_ie + *pout_len, oper_bw); ++ ++ pvhtpriv->vht_option = _TRUE; ++ ++exit: ++ return pvhtpriv->vht_option; ++ ++} ++ ++void VHTOnAssocRsp(_adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u8 ht_AMPDU_len; ++ ++ RTW_INFO("%s\n", __FUNCTION__); ++ ++ if (!pmlmeinfo->HT_enable) ++ return; ++ ++ if (!pmlmeinfo->VHT_enable) ++ return; ++ ++ ht_AMPDU_len = pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x03; ++ ++ if (pvhtpriv->ampdu_len > ht_AMPDU_len) ++ rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&pvhtpriv->ampdu_len)); ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_MAX_TIME, (u8 *)(&pvhtpriv->vht_highest_rate)); ++} ++ ++void rtw_vht_ies_attach(_adapter *padapter, WLAN_BSSID_EX *pnetwork) ++{ ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ u8 cap_len, operation_len; ++ uint len = 0; ++ sint ie_len = 0; ++ u8 *p = NULL; ++ ++ p = rtw_get_ie(pnetwork->IEs + _BEACON_IE_OFFSET_, EID_VHTCapability, &ie_len, ++ (pnetwork->IELength - _BEACON_IE_OFFSET_)); ++ if (p && ie_len > 0) ++ return; ++ ++ rtw_vht_use_default_setting(padapter); ++ ++ /* VHT Operation mode notifiy bit in Extended IE (127) */ ++ SET_EXT_CAPABILITY_ELE_OP_MODE_NOTIF(pmlmepriv->ext_capab_ie_data, 1); ++ pmlmepriv->ext_capab_ie_len = 10; ++ rtw_set_ie(pnetwork->IEs + pnetwork->IELength, EID_EXTCapability, 8, pmlmepriv->ext_capab_ie_data, &len); ++ pnetwork->IELength += pmlmepriv->ext_capab_ie_len; ++ ++ /* VHT Capabilities element */ ++ cap_len = rtw_build_vht_cap_ie(padapter, pnetwork->IEs + pnetwork->IELength); ++ pnetwork->IELength += cap_len; ++ ++ /* VHT Operation element */ ++ operation_len = rtw_build_vht_operation_ie(padapter, pnetwork->IEs + pnetwork->IELength, ++ pnetwork->Configuration.DSConfig); ++ pnetwork->IELength += operation_len; ++ ++ rtw_check_for_vht20(padapter, pnetwork->IEs + _BEACON_IE_OFFSET_, pnetwork->IELength - _BEACON_IE_OFFSET_); ++ ++ pmlmepriv->vhtpriv.vht_option = _TRUE; ++} ++ ++void rtw_vht_ies_detach(_adapter *padapter, WLAN_BSSID_EX *pnetwork) ++{ ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ rtw_remove_bcn_ie(padapter, pnetwork, EID_EXTCapability); ++ rtw_remove_bcn_ie(padapter, pnetwork, EID_VHTCapability); ++ rtw_remove_bcn_ie(padapter, pnetwork, EID_VHTOperation); ++ ++ pmlmepriv->vhtpriv.vht_option = _FALSE; ++} ++ ++void rtw_check_for_vht20(_adapter *adapter, u8 *ies, int ies_len) ++{ ++ u8 ht_ch, ht_bw, ht_offset; ++ u8 vht_ch, vht_bw, vht_offset; ++ ++ rtw_ies_get_chbw(ies, ies_len, &ht_ch, &ht_bw, &ht_offset, 1, 0); ++ rtw_ies_get_chbw(ies, ies_len, &vht_ch, &vht_bw, &vht_offset, 1, 1); ++ ++ if (ht_bw == CHANNEL_WIDTH_20 && vht_bw >= CHANNEL_WIDTH_80) { ++ u8 *vht_op_ie; ++ int vht_op_ielen; ++ ++ RTW_INFO(FUNC_ADPT_FMT" vht80 is not allowed without ht40\n", FUNC_ADPT_ARG(adapter)); ++ vht_op_ie = rtw_get_ie(ies, EID_VHTOperation, &vht_op_ielen, ies_len); ++ if (vht_op_ie && vht_op_ielen) { ++ RTW_INFO(FUNC_ADPT_FMT" switch to vht20\n", FUNC_ADPT_ARG(adapter)); ++ SET_VHT_OPERATION_ELE_CHL_WIDTH(vht_op_ie + 2, 0); ++ SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ1(vht_op_ie + 2, 0); ++ SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ2(vht_op_ie + 2, 0); ++ } ++ } ++} ++#endif /* CONFIG_80211AC_VHT */ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_wlan_util.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_wlan_util.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_wlan_util.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_wlan_util.c 2021-03-07 18:16:17.027954777 +0200 +@@ -0,0 +1,4972 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -110536,7 +107555,6 @@ index 000000000..b4cecd116 + RTW_INFO("[%s] ch = %d, offset = %d, bwmode = %d\n", __func__, channel, channel_offset, bwmode); + + center_ch = rtw_get_center_ch(channel, bwmode, channel_offset); -+ + if (bwmode == CHANNEL_WIDTH_80) { + if (center_ch > channel) + chnl_offset80 = HAL_PRIME_CHNL_OFFSET_LOWER; @@ -114685,7 +111703,9 @@ index 000000000..b4cecd116 + + int i = 0; + struct file *fp; ++#ifdef set_fs + mm_segment_t fs; ++#endif + loff_t pos = 0; + u8 *source = NULL; + long len = 0; @@ -114721,10 +111741,10 @@ index 000000000..b4cecd116 + RTW_INFO("Error, cipher array using default value.\n"); + return 0; + } -+ ++#ifdef set_fs + fs = get_fs(); + set_fs(KERNEL_DS); -+ ++#endif + source = rtw_zmalloc(2048); + + if (source != NULL) { @@ -114732,10 +111752,10 @@ index 000000000..b4cecd116 + rtw_parse_cipher_list(nlo_info, source); + rtw_mfree(source, 2048); + } -+ ++#ifdef set_fs + set_fs(fs); ++#endif + filp_close(fp, NULL); -+ + RTW_INFO("-%s-\n", __func__); + return 0; +} @@ -114910,12 +111930,10 @@ index 000000000..b4cecd116 + /*TODO get offset of bcn's timestamp*/ + /*pmlmeext->bcn_timestamp;*/ +} -diff --git linux-5.8/3rdparty/rtl8812au/core/rtw_xmit.c linux-5.8/3rdparty/rtl8812au/core/rtw_xmit.c -new file mode 100644 -index 000000000..90e215385 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/core/rtw_xmit.c -@@ -0,0 +1,5900 @@ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_xmit.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_xmit.c +--- linux-5.11.4/3rdparty/rtl8812au/core/rtw_xmit.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/core/rtw_xmit.c 2021-03-07 18:16:17.028954824 +0200 +@@ -0,0 +1,6097 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -119319,7 +116337,6 @@ index 000000000..90e215385 +s32 rtw_monitor_xmit_entry(struct sk_buff *skb, struct net_device *ndev) +{ + u16 frame_ctl; -+ struct ieee80211_radiotap_header rtap_hdr; + _adapter *padapter = (_adapter *)rtw_netdev_priv(ndev); + struct pkt_file pktfile; + struct rtw_ieee80211_hdr *pwlanhdr; @@ -119329,37 +116346,49 @@ index 000000000..90e215385 + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct registry_priv *pregpriv = &(padapter->registrypriv); + unsigned char *pframe; -+ u8 dummybuf[32]; -+ int len = skb->len, rtap_len, consume; ++ int len = skb->len; ++ ++ int rtap_len, rtap_remain, ret; ++ struct ieee80211_radiotap_header *rtap_hdr; // net/ieee80211_radiotap.h ++ struct ieee80211_radiotap_iterator iterator; // net/cfg80211.h ++ u8 rtap_buf[256]; + + int alloc_tries, alloc_delay; + + rtw_mstat_update(MSTAT_TYPE_SKB, MSTAT_ALLOC_SUCCESS, skb->truesize); + -+#ifndef CONFIG_CUSTOMER_ALIBABA_GENERAL + if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header))) + goto fail; + + _rtw_open_pktfile((_pkt *)skb, &pktfile); -+ _rtw_pktfile_read(&pktfile, (u8 *)(&rtap_hdr), sizeof(struct ieee80211_radiotap_header)); -+ rtap_len = ieee80211_get_radiotap_len((u8 *)(&rtap_hdr)); -+ if (unlikely(rtap_hdr.it_version)) ++ // Read in radiotap header and sanity check length ++ _rtw_pktfile_read(&pktfile, rtap_buf, sizeof(struct ieee80211_radiotap_header)); ++ rtap_hdr = (struct ieee80211_radiotap_header*)(rtap_buf); ++ rtap_len = ieee80211_get_radiotap_len(rtap_buf); ++ ++ if (unlikely(rtap_hdr->it_version)) + goto fail; + + if (unlikely(skb->len < rtap_len)) + goto fail; + ++ if (unlikely(rtap_len < sizeof(struct ieee80211_radiotap_header))) ++ goto fail; ++ + len -= sizeof(struct ieee80211_radiotap_header); -+ rtap_len -= sizeof(struct ieee80211_radiotap_header); ++ rtap_remain = rtap_len - sizeof(struct ieee80211_radiotap_header); + -+ while(rtap_len) { -+ consume = rtap_len > sizeof(dummybuf) ? sizeof(dummybuf) : rtap_len; -+ _rtw_pktfile_read(&pktfile, dummybuf, consume); -+ rtap_len -= consume; -+ len -= consume; ++ // Read in rest of radiotap body ++ if (rtap_remain) { ++ _rtw_pktfile_read(&pktfile, &rtap_buf[sizeof(struct ieee80211_radiotap_header)], rtap_remain); ++ len -= rtap_remain; + } -+#endif + ++ // NOTE: we process the radiotap header after we update the frame attribs below, ++ // so we can directly apply overrides rather than cache all the values into ++ // variables and apply them later. ++ ++ // Process rest of frame + alloc_delay = 100; + for (alloc_tries=3; alloc_tries > 0; alloc_tries--) { + pmgntframe = alloc_mgtxmitframe(pxmitpriv); @@ -119377,7 +116406,7 @@ index 000000000..90e215385 + _rtw_pktfile_read(&pktfile, pframe, len); + + -+ /* Check DATA/MGNT frames */ ++ // Setup attribs for default Mgmt vs Data frame + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + pattrib = &pmgntframe->attrib; + pattrib->injected = _TRUE; @@ -119411,11 +116440,197 @@ index 000000000..90e215385 + else + pattrib->retry_ctrl = _FALSE; + pattrib->pktlen = len; -+ pmlmeext->mgnt_seq = GetSequence(pwlanhdr); -+ pattrib->seqnum = pmlmeext->mgnt_seq; -+ pmlmeext->mgnt_seq++; ++ + pattrib->last_txcmdsz = pattrib->pktlen; + ++ /* ++ ANALYSIS: most other xmit/frame generation flows: ++ - take next seqnum from pmlmeext->mgnt_seq ++ - call SetSeqNum to write it into the packet ++ - increment pmlmext->mgnt_seq ++ - and set it into pattrib->seqnum ++ Then in HAL, update_txdesc will either use hardware seq number if !pattrib_qos_en, ++ otherwise SET_TX_DESC_SEQ_8812 w/ pattrib->seqnum. ++ Also worth noting is prior update_monitor_frame_attrib/update_mgntframe_attrib call ++ merely set pattrib->seqnum to pmlmeext->mgnt_seq, but do NOT increment mgnt_seq. ++ Also they both set qos_en=_FALSE, which induce HW seq numbers. ++ The code below, however, appears to read the seq num out of the injected packet, ++ update the global pmlmeext->mgnt_seq with the injected seqnum, and then set ++ global pmlmeext to next seq. IMHO it appears to be doing the wrong thing, since ++ it is both updating pmlmeext from data in the packet, and all those values ++ are ignored because qos_en=_FALSE and thus HW seq is just used. ++ Ideally it would be nice to be able to control the sequence number, but the ++ strong coupling to qos_en makes that difficult right now. So we will just ++ use the default HW mode. However, we are going to skip some of the extraneous ++ steps this original code did by simply accepting: ++ - update_*_attrib called prior already set seqnum from pmlmeext ++ - so all we need to do is mgnt_seq++ just in case ++ - (and it seems we can avoid the SetSeqNum call) ++ pmlmeext->mgnt_seq = GetSequence(pwlanhdr); ++ pattrib->seqnum = pmlmeext->mgnt_seq; ++ pmlmeext->mgnt_seq++; ++ */ ++ pmlmeext->mgnt_seq++; ++ ++ pattrib->retry_ctrl = _FALSE; ++ ++ // Parse radiotap for injection items and overwrite attribs as needed ++ ret = ieee80211_radiotap_iterator_init(&iterator, rtap_hdr, rtap_len, NULL); ++ while (!ret) { ++ ret = ieee80211_radiotap_iterator_next(&iterator); ++ if (ret) ++ continue; ++ ++ switch (iterator.this_arg_index) { ++ case IEEE80211_RADIOTAP_RATE: ++ // This is basic 802.11b/g rate; use MCS/VHT for higher rates ++ pattrib->rate = *iterator.this_arg; ++#ifdef CONFIG_80211AC_VHT ++ pattrib->raid = RATEID_IDX_BGN_40M_1SS; ++#else ++ if (pattrib->rate == IEEE80211_CCK_RATE_1MB ++ || pattrib->rate == IEEE80211_CCK_RATE_2MB ++ || pattrib->rate == IEEE80211_CCK_RATE_5MB ++ || pattrib->rate == IEEE80211_CCK_RATE_11MB ) ++ pattrib->raid = rtw_get_mgntframe_raid(padapter, WIRELESS_11B); ++ else ++ pattrib->raid = rtw_get_mgntframe_raid(padapter, WIRELESS_11G); ++#endif ++ ++ // We have to reset other attributes that may have been set prior for MCS/VHT rates ++ pattrib->ht_en = _FALSE; ++ pattrib->ampdu_en = _FALSE; ++ pattrib->sgi = _FALSE; ++ pattrib->ldpc = _FALSE; ++ pattrib->stbc = 0; ++ pattrib->bwmode = CHANNEL_WIDTH_20; ++ pattrib->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ ++ break; ++ ++ case IEEE80211_RADIOTAP_TX_FLAGS: { ++ u16 txflags = get_unaligned_le16(iterator.this_arg); ++ ++ if ((txflags & IEEE80211_RADIOTAP_F_TX_NOACK) == 0) ++ pattrib->retry_ctrl = _TRUE; // Note; already _FALSE by default ++ ++ if (txflags & 0x0010) { // Use preconfigured seq num ++ // NOTE: this is currently ignored due to qos_en=_FALSE and HW seq num override ++ pattrib->seqnum = GetSequence(pwlanhdr); ++ } ++ ++ break; ++ } ++ ++ case IEEE80211_RADIOTAP_MCS: { ++ u8 mcs_have = iterator.this_arg[0]; ++ ++ // Set up defaults ++ pattrib->rate = MGN_MCS0; ++ pattrib->bwmode = IEEE80211_RADIOTAP_MCS_BW_20; ++ pattrib->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ pattrib->ht_en = _TRUE; ++ pattrib->sgi = _FALSE; ++ pattrib->ldpc = _FALSE; ++ pattrib->stbc = 0; ++ ++ if (mcs_have & IEEE80211_RADIOTAP_MCS_HAVE_BW) { ++ ++ u8 bw = (iterator.this_arg[1] & IEEE80211_RADIOTAP_MCS_BW_MASK); ++ if (bw == IEEE80211_RADIOTAP_MCS_BW_20L) { ++ bw = IEEE80211_RADIOTAP_MCS_BW_20; ++ pattrib->ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; ++ } ++ if (bw == IEEE80211_RADIOTAP_MCS_BW_20U) { ++ bw = IEEE80211_RADIOTAP_MCS_BW_20; ++ pattrib->ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; ++ } ++ ++ pattrib->bwmode = bw; ++ } ++ ++ if (mcs_have & IEEE80211_RADIOTAP_MCS_HAVE_MCS) { ++ u8 fixed_rate = iterator.this_arg[2] & 0x7f; ++ if(fixed_rate > 31) ++ fixed_rate = 0; ++ fixed_rate += MGN_MCS0; ++ pattrib->rate = fixed_rate; ++ } ++ ++ if ((mcs_have & IEEE80211_RADIOTAP_MCS_HAVE_GI) && (iterator.this_arg[1] & IEEE80211_RADIOTAP_MCS_SGI)) ++ pattrib->sgi = _TRUE; ++ ++ if ((mcs_have & IEEE80211_RADIOTAP_MCS_HAVE_FEC) && (iterator.this_arg[1] & IEEE80211_RADIOTAP_MCS_FEC_LDPC)) ++ pattrib->ldpc = _TRUE; ++ ++ if (mcs_have & IEEE80211_RADIOTAP_MCS_HAVE_STBC) { ++ u8 stbc = (iterator.this_arg[1] & IEEE80211_RADIOTAP_MCS_STBC_MASK) >> IEEE80211_RADIOTAP_MCS_STBC_SHIFT; ++ pattrib->stbc = stbc; ++ } ++ } ++ break; ++ ++#ifdef CONFIG_80211AC_VHT ++ case IEEE80211_RADIOTAP_VHT: { ++ unsigned int mcs, nss; ++ ++ u8 known = iterator.this_arg[0]; ++ u8 flags = iterator.this_arg[2]; ++ ++ // Set up defaults ++ pattrib->stbc = 0; ++ pattrib->sgi = _FALSE; ++ pattrib->bwmode = CHANNEL_WIDTH_20; ++ pattrib->ldpc = _FALSE; ++ pattrib->rate = MGN_VHT1SS_MCS0; ++ pattrib->raid = RATEID_IDX_VHT_1SS; ++ ++ // NOTE: this code currently only supports 1SS for radiotap defined rates ++ ++ if ((known & IEEE80211_RADIOTAP_VHT_KNOWN_STBC) && (flags & IEEE80211_RADIOTAP_VHT_FLAG_STBC)) ++ pattrib->stbc = 1; ++ ++ if ((known & IEEE80211_RADIOTAP_VHT_KNOWN_GI) && (flags & IEEE80211_RADIOTAP_VHT_FLAG_SGI)) ++ pattrib->sgi = _TRUE; ++ ++ if (known & IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH) { ++ u8 bw = iterator.this_arg[3] & 0x1F; ++ // NOTE: there are various L and U, but we just use straight 20/40/80 ++ // since it's not clear how to set CHNL_OFFSET_LOWER/_UPPER with different ++ // sideband sizes/configurations. TODO. ++ // Also, any 160 is treated as 80 due to lack of WIDTH_160. ++ if (bw == 0) ++ pattrib->bwmode = CHANNEL_WIDTH_20; ++ else if (bw >=1 && bw <= 3) ++ pattrib->bwmode = CHANNEL_WIDTH_40; ++ else if (bw >=4 && bw <= 10) ++ pattrib->bwmode = CHANNEL_WIDTH_80; ++ else if (bw >= 11 && bw <= 25) ++ pattrib->bwmode = CHANNEL_WIDTH_80; // Supposed to be 160Mhz, we use 80Mhz ++ } ++ ++ // User 0 ++ nss = iterator.this_arg[4] & 0x0F; // Number of spatial streams ++ if (nss > 0) { ++ if (nss > 4) nss = 4; ++ mcs = (iterator.this_arg[4]>>4) & 0x0F; // MCS rate index ++ if (mcs > 8) mcs = 9; ++ pattrib->rate = MGN_VHT1SS_MCS0 + ((nss-1)*10 + mcs); ++ ++ if (iterator.this_arg[8] & IEEE80211_RADIOTAP_CODING_LDPC_USER0) ++ pattrib->ldpc = _TRUE; ++ } ++ ++ } ++ break; ++#endif ++ ++ default: ++ break; ++ } ++ } ++ ++ // All set + dump_mgntframe(padapter, pmgntframe); + pxmitpriv->tx_pkts++; + pxmitpriv->tx_bytes += skb->len; @@ -120816,288 +118031,9 @@ index 000000000..90e215385 + RTW_INFO("%s ack_tx not set\n", __func__); +} +#endif /* CONFIG_XMIT_ACK */ -diff --git linux-5.8/3rdparty/rtl8812au/dkms-install.sh linux-5.8/3rdparty/rtl8812au/dkms-install.sh -new file mode 100755 -index 000000000..07c476b7d ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/dkms-install.sh -@@ -0,0 +1,34 @@ -+#!/bin/bash -+ -+if [[ $EUID -ne 0 ]]; then -+ echo "You must run this with superuser priviliges. Try \"sudo ./dkms-install.sh\"" 2>&1 -+ exit 1 -+else -+ echo "About to run dkms install steps..." -+fi -+ -+DRV_DIR="$(pwd)" -+DRV_NAME=rtl8812au -+DRV_VERSION=5.6.4.2 -+ -+cp -r $(pwd) /usr/src/${DRV_NAME}-${DRV_VERSION} -+ -+dkms add -m ${DRV_NAME} -v ${DRV_VERSION} -+dkms build -m ${DRV_NAME} -v ${DRV_VERSION} -+dkms install -m ${DRV_NAME} -v ${DRV_VERSION} -+RESULT=$? -+ -+echo "Finished running dkms install steps." -+ -+if grep -q -e "^CONFIG_DISABLE_IPV6 = y$" "$DRV_DIR/Makefile" ; then -+ if echo "net.ipv6.conf.all.disable_ipv6 = 1 -+ net.ipv6.conf.default.disable_ipv6 = 1 -+ net.ipv6.conf.lo.disable_ipv6 = 1" >> /etc/sysctl.conf; then -+ echo "Disabled IPv6 Successfuly " -+ sysctl -p -+ else -+ echo "Could not disable IPv6" -+ fi -+fi -+ -+exit $RESULT -diff --git linux-5.8/3rdparty/rtl8812au/dkms-remove.sh linux-5.8/3rdparty/rtl8812au/dkms-remove.sh -new file mode 100755 -index 000000000..6a8d6d604 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/dkms-remove.sh -@@ -0,0 +1,24 @@ -+#!/bin/bash -+ -+if [[ $EUID -ne 0 ]]; then -+ echo "You must run this with superuser priviliges. Try \"sudo ./dkms-remove.sh\"" 2>&1 -+ exit 1 -+else -+ echo "About to run dkms removal steps..." -+fi -+ -+DRV_DIR="$(pwd)" -+DRV_NAME=rtl8812au -+DRV_VERSION=5.6.4.2 -+ -+dkms remove ${DRV_NAME}/${DRV_VERSION} --all -+rm -rf /usr/src/${DRV_NAME}-${DRV_VERSION} -+ -+RESULT=$? -+if [[ "$RESULT" != "0" ]]; then -+ echo "Error occurred while running dkms remove." 2>&1 -+else -+ echo "Finished running dkms removal steps." -+fi -+ -+exit $RESULT -diff --git linux-5.8/3rdparty/rtl8812au/dkms.conf linux-5.8/3rdparty/rtl8812au/dkms.conf -new file mode 100644 -index 000000000..4c3c3b7ec ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/dkms.conf -@@ -0,0 +1,10 @@ -+PACKAGE_NAME="realtek-rtl88xxau" -+PACKAGE_VERSION="5.6.4.2~20200816" -+CLEAN="'make' clean" -+BUILT_MODULE_NAME[0]=88XXau -+PROCS_NUM=`nproc` -+[ $PROCS_NUM -gt 16 ] && PROCS_NUM=16 -+DEST_MODULE_LOCATION[0]="/updates" -+MAKE="'make' -j$PROCS_NUM KVER=${kernelver} KSRC=/lib/modules/${kernelver}/build" -+AUTOINSTALL="yes" -+REMAKE_INITRD=no -diff --git linux-5.8/3rdparty/rtl8812au/hal/HalPwrSeqCmd.c linux-5.8/3rdparty/rtl8812au/hal/HalPwrSeqCmd.c -new file mode 100644 -index 000000000..389785c2b ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/HalPwrSeqCmd.c -@@ -0,0 +1,185 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+/*++ -+Copyright (c) Realtek Semiconductor Corp. All rights reserved. -+ -+Module Name: -+ HalPwrSeqCmd.c -+ -+Abstract: -+ Implement HW Power sequence configuration CMD handling routine for Realtek devices. -+ -+Major Change History: -+ When Who What -+ ---------- --------------- ------------------------------- -+ 2011-10-26 Lucas Modify to be compatible with SD4-CE driver. -+ 2011-07-07 Roger Create. -+ -+--*/ -+#include -+ -+ -+/* -+ * Description: -+ * This routine deal with the Power Configuration CMDs parsing for RTL8723/RTL8188E Series IC. -+ * -+ * Assumption: -+ * We should follow specific format which was released from HW SD. -+ * -+ * 2011.07.07, added by Roger. -+ * */ -+u8 HalPwrSeqCmdParsing( -+ PADAPTER padapter, -+ u8 CutVersion, -+ u8 FabVersion, -+ u8 InterfaceType, -+ WLAN_PWR_CFG PwrSeqCmd[]) -+{ -+ WLAN_PWR_CFG PwrCfgCmd = {0}; -+ u8 bPollingBit = _FALSE; -+ u8 bHWICSupport = _FALSE; -+ u32 AryIdx = 0; -+ u8 value = 0; -+ u32 offset = 0; -+ u8 flag = 0; -+ u32 pollingCount = 0; /* polling autoload done. */ -+ u32 maxPollingCnt = 5000; -+ -+ do { -+ PwrCfgCmd = PwrSeqCmd[AryIdx]; -+ -+ -+ /* 2 Only Handle the command whose FAB, CUT, and Interface are matched */ -+ if ((GET_PWR_CFG_FAB_MASK(PwrCfgCmd) & FabVersion) && -+ (GET_PWR_CFG_CUT_MASK(PwrCfgCmd) & CutVersion) && -+ (GET_PWR_CFG_INTF_MASK(PwrCfgCmd) & InterfaceType)) { -+ switch (GET_PWR_CFG_CMD(PwrCfgCmd)) { -+ case PWR_CMD_READ: -+ break; -+ -+ case PWR_CMD_WRITE: -+ offset = GET_PWR_CFG_OFFSET(PwrCfgCmd); -+ -+#ifdef CONFIG_SDIO_HCI -+ /* */ -+ /* We should deal with interface specific address mapping for some interfaces, e.g., SDIO interface */ -+ /* 2011.07.07. */ -+ /* */ -+ if (GET_PWR_CFG_BASE(PwrCfgCmd) == PWR_BASEADDR_SDIO) { -+ /* Read Back SDIO Local value */ -+ value = SdioLocalCmd52Read1Byte(padapter, offset); -+ -+ value &= ~(GET_PWR_CFG_MASK(PwrCfgCmd)); -+ value |= (GET_PWR_CFG_VALUE(PwrCfgCmd) & GET_PWR_CFG_MASK(PwrCfgCmd)); -+ -+ /* Write Back SDIO Local value */ -+ SdioLocalCmd52Write1Byte(padapter, offset, value); -+ } else -+#endif -+ { -+#ifdef CONFIG_GSPI_HCI -+ if (GET_PWR_CFG_BASE(PwrCfgCmd) == PWR_BASEADDR_SDIO) -+ offset = SPI_LOCAL_OFFSET | offset; -+#endif -+ /* Read the value from system register */ -+ value = rtw_read8(padapter, offset); -+ -+ value = value & (~(GET_PWR_CFG_MASK(PwrCfgCmd))); -+ value = value | (GET_PWR_CFG_VALUE(PwrCfgCmd) & GET_PWR_CFG_MASK(PwrCfgCmd)); -+ -+ /* Write the value back to sytem register */ -+ rtw_write8(padapter, offset, value); -+ } -+ break; -+ -+ case PWR_CMD_POLLING: -+ -+ bPollingBit = _FALSE; -+ offset = GET_PWR_CFG_OFFSET(PwrCfgCmd); -+ -+ rtw_hal_get_hwreg(padapter, HW_VAR_PWR_CMD, &bHWICSupport); -+ if (bHWICSupport && offset == 0x06) { -+ flag = 0; -+ maxPollingCnt = 100000; -+ } else -+ maxPollingCnt = 5000; -+ -+#ifdef CONFIG_GSPI_HCI -+ if (GET_PWR_CFG_BASE(PwrCfgCmd) == PWR_BASEADDR_SDIO) -+ offset = SPI_LOCAL_OFFSET | offset; -+#endif -+ do { -+#ifdef CONFIG_SDIO_HCI -+ if (GET_PWR_CFG_BASE(PwrCfgCmd) == PWR_BASEADDR_SDIO) -+ value = SdioLocalCmd52Read1Byte(padapter, offset); -+ else -+#endif -+ value = rtw_read8(padapter, offset); -+ -+ value = value & GET_PWR_CFG_MASK(PwrCfgCmd); -+ if (value == (GET_PWR_CFG_VALUE(PwrCfgCmd) & GET_PWR_CFG_MASK(PwrCfgCmd))) -+ bPollingBit = _TRUE; -+ else -+ rtw_udelay_os(10); -+ -+ if (pollingCount++ > maxPollingCnt) { -+ RTW_ERR("HalPwrSeqCmdParsing: Fail to polling Offset[%#x]=%02x\n", offset, value); -+ -+ /* For PCIE + USB package poll power bit timeout issue only modify 8821AE and 8723BE */ -+ if (bHWICSupport && offset == 0x06 && flag == 0) { -+ -+ RTW_ERR("[WARNING] PCIE polling(0x%X) timeout(%d), Toggle 0x04[3] and try again.\n", offset, maxPollingCnt); -+ if (IS_HARDWARE_TYPE_8723DE(padapter)) -+ PlatformEFIOWrite1Byte(padapter, 0x40, (PlatformEFIORead1Byte(padapter, 0x40)) & (~BIT3)); -+ -+ PlatformEFIOWrite1Byte(padapter, 0x04, PlatformEFIORead1Byte(padapter, 0x04) | BIT3); -+ PlatformEFIOWrite1Byte(padapter, 0x04, PlatformEFIORead1Byte(padapter, 0x04) & ~BIT3); -+ -+ if (IS_HARDWARE_TYPE_8723DE(padapter)) -+ PlatformEFIOWrite1Byte(padapter, 0x40, PlatformEFIORead1Byte(padapter, 0x40)|BIT3); -+ -+ /* Retry Polling Process one more time */ -+ pollingCount = 0; -+ flag = 1; -+ } else { -+ return _FALSE; -+ } -+ } -+ } while (!bPollingBit); -+ -+ break; -+ -+ case PWR_CMD_DELAY: -+ if (GET_PWR_CFG_VALUE(PwrCfgCmd) == PWRSEQ_DELAY_US) -+ rtw_udelay_os(GET_PWR_CFG_OFFSET(PwrCfgCmd)); -+ else -+ rtw_udelay_os(GET_PWR_CFG_OFFSET(PwrCfgCmd) * 1000); -+ break; -+ -+ case PWR_CMD_END: -+ /* When this command is parsed, end the process */ -+ return _TRUE; -+ break; -+ -+ default: -+ break; -+ } -+ } -+ -+ AryIdx++;/* Add Array Index */ -+ } while (1); -+ -+ return _TRUE; -+} -diff --git linux-5.8/3rdparty/rtl8812au/hal/efuse/efuse_mask.h linux-5.8/3rdparty/rtl8812au/hal/efuse/efuse_mask.h -new file mode 100644 -index 000000000..f6059e4ec ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/efuse/efuse_mask.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/efuse/efuse_mask.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/efuse/efuse_mask.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/efuse/efuse_mask.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/efuse/efuse_mask.h 2021-03-07 18:16:17.049955817 +0200 @@ -0,0 +1,164 @@ +/****************************************************************************** + * @@ -121263,11 +118199,9 @@ index 000000000..f6059e4ec + #endif + +#endif /*CONFIG_SDIO_HCI*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_PCIE.c linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_PCIE.c -new file mode 100644 -index 000000000..2b4d32648 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_PCIE.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_PCIE.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_PCIE.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_PCIE.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_PCIE.c 2021-03-07 18:16:17.049955817 +0200 @@ -0,0 +1,94 @@ +/****************************************************************************** + * @@ -121363,11 +118297,9 @@ index 000000000..2b4d32648 + + return (result > 0) ? 0 : 1; +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_PCIE.h linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_PCIE.h -new file mode 100644 -index 000000000..085b2054c ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_PCIE.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_PCIE.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_PCIE.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_PCIE.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_PCIE.h 2021-03-07 18:16:17.049955817 +0200 @@ -0,0 +1,33 @@ +/****************************************************************************** + * @@ -121402,11 +118334,9 @@ index 000000000..085b2054c +EFUSE_IsAddressMasked_MP_8812A_MPCIE(/* TC: Test Chip, MP: MP Chip */ + IN u2Byte Offset +); -diff --git linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_USB.c linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_USB.c -new file mode 100644 -index 000000000..fd66e88e3 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_USB.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_USB.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_USB.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_USB.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_USB.c 2021-03-07 18:16:17.049955817 +0200 @@ -0,0 +1,94 @@ +/****************************************************************************** + * @@ -121502,11 +118432,9 @@ index 000000000..fd66e88e3 + + return (result > 0) ? 0 : 1; +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_USB.h linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_USB.h -new file mode 100644 -index 000000000..1adfd8189 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_USB.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_USB.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_USB.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_USB.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_USB.h 2021-03-07 18:16:17.049955817 +0200 @@ -0,0 +1,34 @@ +/****************************************************************************** + * @@ -121542,11 +118470,9 @@ index 000000000..1adfd8189 +EFUSE_IsAddressMasked_MP_8812A_MUSB(/* TC: Test Chip, MP: MP Chip */ + IN u2Byte Offset +); -diff --git linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_PCIE.c linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_PCIE.c -new file mode 100644 -index 000000000..608f35ec9 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_PCIE.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_PCIE.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_PCIE.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_PCIE.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_PCIE.c 2021-03-07 18:16:17.049955817 +0200 @@ -0,0 +1,93 @@ +/****************************************************************************** + * @@ -121641,11 +118567,9 @@ index 000000000..608f35ec9 + + return (result > 0) ? 0 : 1; +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_PCIE.h linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_PCIE.h -new file mode 100644 -index 000000000..7e46d8e3c ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_PCIE.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_PCIE.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_PCIE.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_PCIE.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_PCIE.h 2021-03-07 18:16:17.049955817 +0200 @@ -0,0 +1,33 @@ +/****************************************************************************** + * @@ -121680,11 +118604,9 @@ index 000000000..7e46d8e3c +EFUSE_IsAddressMasked_MP_8821A_MPCIE(/* TC: Test Chip, MP: MP Chip */ + IN u2Byte Offset +); -diff --git linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_SDIO.c linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_SDIO.c -new file mode 100644 -index 000000000..bc9a28d18 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_SDIO.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_SDIO.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_SDIO.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_SDIO.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_SDIO.c 2021-03-07 18:16:17.049955817 +0200 @@ -0,0 +1,96 @@ +/****************************************************************************** + * @@ -121782,11 +118704,9 @@ index 000000000..bc9a28d18 + + return (result > 0) ? 0 : 1; +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_SDIO.h linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_SDIO.h -new file mode 100644 -index 000000000..d82abe474 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_SDIO.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_SDIO.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_SDIO.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_SDIO.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_SDIO.h 2021-03-07 18:16:17.049955817 +0200 @@ -0,0 +1,31 @@ +/****************************************************************************** + * @@ -121819,11 +118739,9 @@ index 000000000..d82abe474 +EFUSE_IsAddressMasked_MP_8821A_MSDIO(/* TC: Test Chip, MP: MP Chip */ + IN u2Byte Offset +); -diff --git linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_USB.c linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_USB.c -new file mode 100644 -index 000000000..36af57559 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_USB.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_USB.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_USB.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_USB.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_USB.c 2021-03-07 18:16:17.049955817 +0200 @@ -0,0 +1,95 @@ +/****************************************************************************** + * @@ -121920,11 +118838,9 @@ index 000000000..36af57559 + + return (result > 0) ? 0 : 1; +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_USB.h linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_USB.h -new file mode 100644 -index 000000000..728f2d5a3 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_USB.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_USB.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_USB.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_USB.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_USB.h 2021-03-07 18:16:17.049955817 +0200 @@ -0,0 +1,31 @@ +/****************************************************************************** + * @@ -121957,11 +118873,9 @@ index 000000000..728f2d5a3 +EFUSE_IsAddressMasked_MP_8821A_MUSB(/* TC: Test Chip, MP: MP Chip */ + IN u2Byte Offset +); -diff --git linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_PCIE.c linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_PCIE.c -new file mode 100644 -index 000000000..22f793cc3 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_PCIE.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_PCIE.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_PCIE.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_PCIE.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_PCIE.c 2021-03-07 18:16:17.049955817 +0200 @@ -0,0 +1,93 @@ +/****************************************************************************** +* @@ -122056,11 +118970,9 @@ index 000000000..22f793cc3 + return (result > 0) ? 0 : 1; +} + -diff --git linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_PCIE.h linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_PCIE.h -new file mode 100644 -index 000000000..8b51c1b4a ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_PCIE.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_PCIE.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_PCIE.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_PCIE.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_PCIE.h 2021-03-07 18:16:17.049955817 +0200 @@ -0,0 +1,33 @@ +/****************************************************************************** +* @@ -122095,11 +119007,9 @@ index 000000000..8b51c1b4a +BOOLEAN EFUSE_IsAddressMasked_MP_8814A_MPCIE(u2Byte Offset); + + -diff --git linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_USB.c linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_USB.c -new file mode 100644 -index 000000000..cd80e9294 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_USB.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_USB.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_USB.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_USB.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_USB.c 2021-03-07 18:16:17.049955817 +0200 @@ -0,0 +1,90 @@ +/****************************************************************************** +* @@ -122191,11 +119101,9 @@ index 000000000..cd80e9294 + return (result > 0) ? 0 : 1; +} + -diff --git linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_USB.h linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_USB.h -new file mode 100644 -index 000000000..4262400d7 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_USB.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_USB.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_USB.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_USB.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_USB.h 2021-03-07 18:16:17.049955817 +0200 @@ -0,0 +1,33 @@ +/****************************************************************************** +* @@ -122230,11 +119138,9 @@ index 000000000..4262400d7 + +BOOLEAN EFUSE_IsAddressMasked_MP_8814A_MUSB(u2Byte Offset); + -diff --git linux-5.8/3rdparty/rtl8812au/hal/hal_btcoex.c linux-5.8/3rdparty/rtl8812au/hal/hal_btcoex.c -new file mode 100644 -index 000000000..bb0c3dc1a ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/hal_btcoex.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_btcoex.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_btcoex.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/hal_btcoex.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_btcoex.c 2021-03-07 18:16:17.049955817 +0200 @@ -0,0 +1,5706 @@ +/****************************************************************************** + * @@ -127942,11 +124848,9 @@ index 000000000..bb0c3dc1a + EXhalbtcoutsrc_rx_rate_change_notify(&GLBtCoexist, is_data_frame, EXhalbtcoutsrc_rate_id_to_btc_rate_id(rate_id)); +} +#endif /* CONFIG_BT_COEXIST */ -diff --git linux-5.8/3rdparty/rtl8812au/hal/hal_btcoex_wifionly.c linux-5.8/3rdparty/rtl8812au/hal/hal_btcoex_wifionly.c -new file mode 100644 -index 000000000..0f82bbbb8 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/hal_btcoex_wifionly.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_btcoex_wifionly.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_btcoex_wifionly.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/hal_btcoex_wifionly.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_btcoex_wifionly.c 2021-03-07 18:16:17.049955817 +0200 @@ -0,0 +1,224 @@ +/****************************************************************************** + * @@ -128172,11 +125076,9 @@ index 000000000..0f82bbbb8 + +#endif + -diff --git linux-5.8/3rdparty/rtl8812au/hal/hal_com.c linux-5.8/3rdparty/rtl8812au/hal/hal_com.c -new file mode 100644 -index 000000000..dcf8edf4a ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/hal_com.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_com.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_com.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/hal_com.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_com.c 2021-03-07 18:16:17.051955911 +0200 @@ -0,0 +1,14640 @@ +/****************************************************************************** + * @@ -142818,11 +139720,9 @@ index 000000000..dcf8edf4a +} +#endif /*CONFIG_RTL8812A*/ + -diff --git linux-5.8/3rdparty/rtl8812au/hal/hal_com_c2h.h linux-5.8/3rdparty/rtl8812au/hal/hal_com_c2h.h -new file mode 100644 -index 000000000..1efabc9dc ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/hal_com_c2h.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_com_c2h.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_com_c2h.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/hal_com_c2h.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_com_c2h.h 2021-03-07 18:16:17.051955911 +0200 @@ -0,0 +1,123 @@ +/****************************************************************************** + * @@ -142947,11 +139847,9 @@ index 000000000..1efabc9dc +#endif + +#endif /* __COMMON_C2H_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/hal/hal_com_phycfg.c linux-5.8/3rdparty/rtl8812au/hal/hal_com_phycfg.c -new file mode 100644 -index 000000000..ada38b221 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/hal_com_phycfg.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_com_phycfg.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_com_phycfg.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/hal_com_phycfg.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_com_phycfg.c 2021-03-07 18:16:17.051955911 +0200 @@ -0,0 +1,5408 @@ +/****************************************************************************** + * @@ -148361,11 +145259,740 @@ index 000000000..ada38b221 +} + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/hal_dm.c linux-5.8/3rdparty/rtl8812au/hal/hal_dm.c -new file mode 100644 -index 000000000..c5fa43e30 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/hal_dm.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_dm_acs.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_dm_acs.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/hal_dm_acs.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_dm_acs.c 2021-03-07 18:16:17.051955911 +0200 +@@ -0,0 +1,556 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2014 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++#include ++#include ++ ++ ++#if defined(CONFIG_RTW_ACS) || defined(CONFIG_BACKGROUND_NOISE_MONITOR) ++static void _rtw_bss_nums_count(_adapter *adapter, u8 *pbss_nums) ++{ ++ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); ++ _queue *queue = &(pmlmepriv->scanned_queue); ++ struct wlan_network *pnetwork = NULL; ++ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); ++ ++ _list *plist, *phead; ++ _irqL irqL; ++ int chan_idx = -1; ++ ++ if (pbss_nums == NULL) { ++ RTW_ERR("%s pbss_nums is null pointer\n", __func__); ++ return; ++ } ++ _rtw_memset(pbss_nums, 0, MAX_CHANNEL_NUM); ++ ++ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ phead = get_list_head(queue); ++ plist = get_next(phead); ++ while (1) { ++ if (rtw_end_of_queue_search(phead, plist) == _TRUE) ++ break; ++ ++ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); ++ if (!pnetwork) ++ break; ++ chan_idx = rtw_chset_search_ch(adapter_to_chset(adapter), pnetwork->network.Configuration.DSConfig); ++ if ((chan_idx == -1) || (chan_idx >= MAX_CHANNEL_NUM)) { ++ RTW_ERR("%s can't get chan_idx(CH:%d)\n", ++ __func__, pnetwork->network.Configuration.DSConfig); ++ chan_idx = 0; ++ } ++ /*if (pnetwork->network.Reserved[0] != BSS_TYPE_PROB_REQ)*/ ++ ++ pbss_nums[chan_idx]++; ++ ++ plist = get_next(plist); ++ } ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++} ++ ++u8 rtw_get_ch_num_by_idx(_adapter *adapter, u8 idx) ++{ ++ struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter); ++ RT_CHANNEL_INFO *pch_set = rfctl->channel_set; ++ u8 max_chan_nums = rfctl->max_chan_nums; ++ ++ if (idx >= max_chan_nums) ++ return 0; ++ return pch_set[idx].ChannelNum; ++} ++#endif /*defined(CONFIG_RTW_ACS) || defined(CONFIG_BACKGROUND_NOISE_MONITOR)*/ ++ ++ ++#ifdef CONFIG_RTW_ACS ++void rtw_acs_version_dump(void *sel, _adapter *adapter) ++{ ++ _RTW_PRINT_SEL(sel, "RTK_ACS VER_%d\n", RTK_ACS_VERSION); ++} ++u8 rtw_phydm_clm_ratio(_adapter *adapter) ++{ ++ struct dm_struct *phydm = adapter_to_phydm(adapter); ++ ++ return phydm_cmn_info_query(phydm, (enum phydm_info_query) PHYDM_INFO_CLM_RATIO); ++} ++u8 rtw_phydm_nhm_ratio(_adapter *adapter) ++{ ++ struct dm_struct *phydm = adapter_to_phydm(adapter); ++ ++ return phydm_cmn_info_query(phydm, (enum phydm_info_query) PHYDM_INFO_NHM_RATIO); ++} ++void rtw_acs_reset(_adapter *adapter) ++{ ++ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); ++ struct auto_chan_sel *pacs = &hal_data->acs; ++ ++ _rtw_memset(pacs, 0, sizeof(struct auto_chan_sel)); ++ #ifdef CONFIG_RTW_ACS_DBG ++ rtw_acs_adv_reset(adapter); ++ #endif /*CONFIG_RTW_ACS_DBG*/ ++} ++ ++#ifdef CONFIG_RTW_ACS_DBG ++u8 rtw_is_acs_igi_valid(_adapter *adapter) ++{ ++ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); ++ struct auto_chan_sel *pacs = &hal_data->acs; ++ ++ if ((pacs->igi) && ((pacs->igi >= 0x1E) || (pacs->igi < 0x60))) ++ return _TRUE; ++ ++ return _FALSE; ++} ++void rtw_acs_adv_setting(_adapter *adapter, RT_SCAN_TYPE scan_type, u16 scan_time, u8 igi, u8 bw) ++{ ++ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); ++ struct auto_chan_sel *pacs = &hal_data->acs; ++ struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ pacs->scan_type = scan_type; ++ pacs->scan_time = scan_time; ++ pacs->igi = igi; ++ pacs->bw = bw; ++ RTW_INFO("[ACS] ADV setting - scan_type:%c, ch_ms:%d(ms), igi:0x%02x, bw:%d\n", ++ pacs->scan_type ? 'A' : 'P', pacs->scan_time, pacs->igi, pacs->bw); ++} ++void rtw_acs_adv_reset(_adapter *adapter) ++{ ++ rtw_acs_adv_setting(adapter, SCAN_ACTIVE, 0, 0, 0); ++} ++#endif /*CONFIG_RTW_ACS_DBG*/ ++ ++void rtw_acs_trigger(_adapter *adapter, u16 scan_time_ms, u8 scan_chan, enum NHM_PID pid) ++{ ++ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); ++ struct dm_struct *phydm = adapter_to_phydm(adapter); ++#if (RTK_ACS_VERSION == 3) ++ struct clm_para_info clm_para; ++ struct nhm_para_info nhm_para; ++ struct env_trig_rpt trig_rpt; ++ ++ scan_time_ms -= 10; ++ ++ init_acs_clm(clm_para, scan_time_ms); ++ ++ if (pid == NHM_PID_IEEE_11K_HIGH) ++ init_11K_high_nhm(nhm_para, scan_time_ms); ++ else if (pid == NHM_PID_IEEE_11K_LOW) ++ init_11K_low_nhm(nhm_para, scan_time_ms); ++ else ++ init_acs_nhm(nhm_para, scan_time_ms); ++ ++ hal_data->acs.trig_rst = phydm_env_mntr_trigger(phydm, &nhm_para, &clm_para, &trig_rpt); ++ if (hal_data->acs.trig_rst == (NHM_SUCCESS | CLM_SUCCESS)) { ++ hal_data->acs.trig_rpt.clm_rpt_stamp = trig_rpt.clm_rpt_stamp; ++ hal_data->acs.trig_rpt.nhm_rpt_stamp = trig_rpt.nhm_rpt_stamp; ++ /*RTW_INFO("[ACS] trigger success (rst = 0x%02x, clm_stamp:%d, nhm_stamp:%d)\n", ++ hal_data->acs.trig_rst, hal_data->acs.trig_rpt.clm_rpt_stamp, hal_data->acs.trig_rpt.nhm_rpt_stamp);*/ ++ } else ++ RTW_ERR("[ACS] trigger failed (rst = 0x%02x)\n", hal_data->acs.trig_rst); ++#else ++ phydm_ccx_monitor_trigger(phydm, scan_time_ms); ++#endif ++ ++ hal_data->acs.trigger_ch = scan_chan; ++ hal_data->acs.triggered = _TRUE; ++ ++ #ifdef CONFIG_RTW_ACS_DBG ++ RTW_INFO("[ACS] Trigger CH:%d, Times:%d\n", hal_data->acs.trigger_ch, scan_time_ms); ++ #endif ++} ++void rtw_acs_get_rst(_adapter *adapter) ++{ ++ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); ++ struct dm_struct *phydm = adapter_to_phydm(adapter); ++ int chan_idx = -1; ++ u8 cur_chan = hal_data->acs.trigger_ch; ++ ++ if (cur_chan == 0) ++ return; ++ ++ if (!hal_data->acs.triggered) ++ return; ++ ++ chan_idx = rtw_chset_search_ch(adapter_to_chset(adapter), cur_chan); ++ if ((chan_idx == -1) || (chan_idx >= MAX_CHANNEL_NUM)) { ++ RTW_ERR("[ACS] %s can't get chan_idx(CH:%d)\n", __func__, cur_chan); ++ return; ++ } ++#if (RTK_ACS_VERSION == 3) ++ if (!(hal_data->acs.trig_rst == (NHM_SUCCESS | CLM_SUCCESS))) { ++ RTW_ERR("[ACS] get_rst return, due to acs trigger failed\n"); ++ return; ++ } ++ ++ { ++ struct env_mntr_rpt rpt = {0}; ++ u8 rst; ++ ++ rst = phydm_env_mntr_result(phydm, &rpt); ++ if ((rst == (NHM_SUCCESS | CLM_SUCCESS)) && ++ (rpt.clm_rpt_stamp == hal_data->acs.trig_rpt.clm_rpt_stamp) && ++ (rpt.nhm_rpt_stamp == hal_data->acs.trig_rpt.nhm_rpt_stamp)){ ++ hal_data->acs.clm_ratio[chan_idx] = rpt.clm_ratio; ++ hal_data->acs.nhm_ratio[chan_idx] = rpt.nhm_ratio; ++ _rtw_memcpy(&hal_data->acs.nhm[chan_idx][0], rpt.nhm_result, NHM_RPT_NUM); ++ ++ /*RTW_INFO("[ACS] get_rst success (rst = 0x%02x, clm_stamp:%d:%d, nhm_stamp:%d:%d)\n", ++ rst, ++ hal_data->acs.trig_rpt.clm_rpt_stamp, rpt.clm_rpt_stamp, ++ hal_data->acs.trig_rpt.nhm_rpt_stamp, rpt.nhm_rpt_stamp);*/ ++ } else { ++ RTW_ERR("[ACS] get_rst failed (rst = 0x%02x, clm_stamp:%d:%d, nhm_stamp:%d:%d)\n", ++ rst, ++ hal_data->acs.trig_rpt.clm_rpt_stamp, rpt.clm_rpt_stamp, ++ hal_data->acs.trig_rpt.nhm_rpt_stamp, rpt.nhm_rpt_stamp); ++ } ++ } ++ ++#else ++ phydm_ccx_monitor_result(phydm); ++ ++ hal_data->acs.clm_ratio[chan_idx] = rtw_phydm_clm_ratio(adapter); ++ hal_data->acs.nhm_ratio[chan_idx] = rtw_phydm_nhm_ratio(adapter); ++#endif ++ hal_data->acs.triggered = _FALSE; ++ #ifdef CONFIG_RTW_ACS_DBG ++ RTW_INFO("[ACS] Result CH:%d, CLM:%d NHM:%d\n", ++ cur_chan, hal_data->acs.clm_ratio[chan_idx], hal_data->acs.nhm_ratio[chan_idx]); ++ #endif ++} ++ ++void _rtw_phydm_acs_select_best_chan(_adapter *adapter) ++{ ++ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); ++ struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter); ++ u8 ch_idx; ++ u8 ch_idx_24g = 0xFF, ch_idx_5g = 0xFF; ++ u8 min_itf_24g = 0xFF, min_itf_5g = 0xFF; ++ u8 *pbss_nums = hal_data->acs.bss_nums; ++ u8 *pclm_ratio = hal_data->acs.clm_ratio; ++ u8 *pnhm_ratio = hal_data->acs.nhm_ratio; ++ u8 *pinterference_time = hal_data->acs.interference_time; ++ u8 max_chan_nums = rfctl->max_chan_nums; ++ ++ for (ch_idx = 0; ch_idx < max_chan_nums; ch_idx++) { ++ if (pbss_nums[ch_idx]) ++ pinterference_time[ch_idx] = (pclm_ratio[ch_idx] / 2) + pnhm_ratio[ch_idx]; ++ else ++ pinterference_time[ch_idx] = pclm_ratio[ch_idx] + pnhm_ratio[ch_idx]; ++ ++ if (rtw_get_ch_num_by_idx(adapter, ch_idx) < 14) { ++ if (pinterference_time[ch_idx] < min_itf_24g) { ++ min_itf_24g = pinterference_time[ch_idx]; ++ ch_idx_24g = ch_idx; ++ } ++ } else { ++ if (pinterference_time[ch_idx] < min_itf_5g) { ++ min_itf_5g = pinterference_time[ch_idx]; ++ ch_idx_5g = ch_idx; ++ } ++ } ++ } ++ if (ch_idx_24g != 0xFF) ++ hal_data->acs.best_chan_24g = rtw_get_ch_num_by_idx(adapter, ch_idx_24g); ++ ++ if (ch_idx_5g != 0xFF) ++ hal_data->acs.best_chan_5g = rtw_get_ch_num_by_idx(adapter, ch_idx_5g); ++ ++ hal_data->acs.trigger_ch = 0; ++} ++ ++void rtw_acs_info_dump(void *sel, _adapter *adapter) ++{ ++ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); ++ struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter); ++ u8 max_chan_nums = rfctl->max_chan_nums; ++ u8 ch_idx, ch_num; ++ ++ _RTW_PRINT_SEL(sel, "========== ACS (VER-%d) ==========\n", RTK_ACS_VERSION); ++ _RTW_PRINT_SEL(sel, "Best 24G Channel:%d\n", hal_data->acs.best_chan_24g); ++ _RTW_PRINT_SEL(sel, "Best 5G Channel:%d\n\n", hal_data->acs.best_chan_5g); ++ ++ #ifdef CONFIG_RTW_ACS_DBG ++ _RTW_PRINT_SEL(sel, "Advanced setting - scan_type:%c, ch_ms:%d(ms), igi:0x%02x, bw:%d\n", ++ hal_data->acs.scan_type ? 'A' : 'P', hal_data->acs.scan_time, hal_data->acs.igi, hal_data->acs.bw); ++ ++ _RTW_PRINT_SEL(sel, "BW 20MHz\n"); ++ _RTW_PRINT_SEL(sel, "%5s %3s %3s %3s(%%) %3s(%%) %3s\n", ++ "Index", "CH", "BSS", "CLM", "NHM", "ITF"); ++ ++ for (ch_idx = 0; ch_idx < max_chan_nums; ch_idx++) { ++ ch_num = rtw_get_ch_num_by_idx(adapter, ch_idx); ++ _RTW_PRINT_SEL(sel, "%5d %3d %3d %6d %6d %3d\n", ++ ch_idx, ch_num, hal_data->acs.bss_nums[ch_idx], ++ hal_data->acs.clm_ratio[ch_idx], ++ hal_data->acs.nhm_ratio[ch_idx], ++ hal_data->acs.interference_time[ch_idx]); ++ } ++ #endif ++} ++void rtw_acs_select_best_chan(_adapter *adapter) ++{ ++ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); ++ ++ _rtw_bss_nums_count(adapter, hal_data->acs.bss_nums); ++ _rtw_phydm_acs_select_best_chan(adapter); ++ rtw_acs_info_dump(RTW_DBGDUMP, adapter); ++} ++ ++void rtw_acs_start(_adapter *adapter) ++{ ++ rtw_acs_reset(adapter); ++ if (GET_ACS_STATE(adapter) != ACS_ENABLE) ++ SET_ACS_STATE(adapter, ACS_ENABLE); ++} ++void rtw_acs_stop(_adapter *adapter) ++{ ++ SET_ACS_STATE(adapter, ACS_DISABLE); ++} ++ ++ ++u8 rtw_acs_get_clm_ratio_by_ch_num(_adapter *adapter, u8 chan) ++{ ++ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); ++ int chan_idx = -1; ++ ++ chan_idx = rtw_chset_search_ch(adapter_to_chset(adapter), chan); ++ if ((chan_idx == -1) || (chan_idx >= MAX_CHANNEL_NUM)) { ++ RTW_ERR("[ACS] Get CLM fail, can't get chan_idx(CH:%d)\n", chan); ++ return 0; ++ } ++ ++ return hal_data->acs.clm_ratio[chan_idx]; ++} ++u8 rtw_acs_get_clm_ratio_by_ch_idx(_adapter *adapter, u8 ch_idx) ++{ ++ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); ++ ++ if (ch_idx >= MAX_CHANNEL_NUM) { ++ RTW_ERR("%s [ACS] ch_idx(%d) is invalid\n", __func__, ch_idx); ++ return 0; ++ } ++ ++ return hal_data->acs.clm_ratio[ch_idx]; ++} ++u8 rtw_acs_get_nhm_ratio_by_ch_num(_adapter *adapter, u8 chan) ++{ ++ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); ++ int chan_idx = -1; ++ ++ chan_idx = rtw_chset_search_ch(adapter_to_chset(adapter), chan); ++ if ((chan_idx == -1) || (chan_idx >= MAX_CHANNEL_NUM)) { ++ RTW_ERR("[ACS] Get NHM fail, can't get chan_idx(CH:%d)\n", chan); ++ return 0; ++ } ++ ++ return hal_data->acs.nhm_ratio[chan_idx]; ++} ++u8 rtw_acs_get_num_ratio_by_ch_idx(_adapter *adapter, u8 ch_idx) ++{ ++ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); ++ ++ if (ch_idx >= MAX_CHANNEL_NUM) { ++ RTW_ERR("%s [ACS] ch_idx(%d) is invalid\n", __func__, ch_idx); ++ return 0; ++ } ++ ++ return hal_data->acs.nhm_ratio[ch_idx]; ++} ++void rtw_acs_chan_info_dump(void *sel, _adapter *adapter) ++{ ++ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); ++ struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter); ++ u8 max_chan_nums = rfctl->max_chan_nums; ++ u8 ch_idx, ch_num; ++ u8 utilization; ++ ++ _RTW_PRINT_SEL(sel, "BW 20MHz\n"); ++ _RTW_PRINT_SEL(sel, "%5s %3s %7s(%%) %12s(%%) %11s(%%) %9s(%%) %8s(%%)\n", ++ "Index", "CH", "Quality", "Availability", "Utilization", ++ "WIFI Util", "Interference Util"); ++ ++ for (ch_idx = 0; ch_idx < max_chan_nums; ch_idx++) { ++ ch_num = rtw_get_ch_num_by_idx(adapter, ch_idx); ++ utilization = hal_data->acs.clm_ratio[ch_idx] + hal_data->acs.nhm_ratio[ch_idx]; ++ _RTW_PRINT_SEL(sel, "%5d %3d %7d %12d %12d %12d %12d\n", ++ ch_idx, ch_num, ++ (100-hal_data->acs.interference_time[ch_idx]), ++ (100-utilization), ++ utilization, ++ hal_data->acs.clm_ratio[ch_idx], ++ hal_data->acs.nhm_ratio[ch_idx]); ++ } ++} ++void rtw_acs_current_info_dump(void *sel, _adapter *adapter) ++{ ++ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); ++ u8 ch, cen_ch, bw, offset; ++ ++ _RTW_PRINT_SEL(sel, "========== ACS (VER-%d) ==========\n", RTK_ACS_VERSION); ++ ++ ch = rtw_get_oper_ch(adapter); ++ bw = rtw_get_oper_bw(adapter); ++ offset = rtw_get_oper_choffset(adapter); ++ ++ _RTW_PRINT_SEL(sel, "Current Channel:%d\n", ch); ++ if ((bw == CHANNEL_WIDTH_80) ||(bw == CHANNEL_WIDTH_40)) { ++ cen_ch = rtw_get_center_ch(ch, bw, offset); ++ _RTW_PRINT_SEL(sel, "Center Channel:%d\n", cen_ch); ++ } ++ ++ _RTW_PRINT_SEL(sel, "Current BW %s\n", ch_width_str(bw)); ++ if (0) ++ _RTW_PRINT_SEL(sel, "Current IGI 0x%02x\n", rtw_phydm_get_cur_igi(adapter)); ++ _RTW_PRINT_SEL(sel, "CLM:%d, NHM:%d\n\n", ++ hal_data->acs.cur_ch_clm_ratio, hal_data->acs.cur_ch_nhm_ratio); ++} ++ ++void rtw_acs_update_current_info(_adapter *adapter) ++{ ++ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); ++ ++ hal_data->acs.cur_ch_clm_ratio = rtw_phydm_clm_ratio(adapter); ++ hal_data->acs.cur_ch_nhm_ratio = rtw_phydm_nhm_ratio(adapter); ++ ++ #ifdef CONFIG_RTW_ACS_DBG ++ rtw_acs_current_info_dump(RTW_DBGDUMP, adapter); ++ #endif ++} ++#endif /*CONFIG_RTW_ACS*/ ++ ++#ifdef CONFIG_BACKGROUND_NOISE_MONITOR ++void rtw_noise_monitor_version_dump(void *sel, _adapter *adapter) ++{ ++ _RTW_PRINT_SEL(sel, "RTK_NOISE_MONITOR VER_%d\n", RTK_NOISE_MONITOR_VERSION); ++} ++void rtw_nm_enable(_adapter *adapter) ++{ ++ SET_NM_STATE(adapter, NM_ENABLE); ++} ++void rtw_nm_disable(_adapter *adapter) ++{ ++ SET_NM_STATE(adapter, NM_DISABLE); ++} ++void rtw_noise_info_dump(void *sel, _adapter *adapter) ++{ ++ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); ++ struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter); ++ u8 max_chan_nums = rfctl->max_chan_nums; ++ u8 ch_idx, ch_num; ++ ++ _RTW_PRINT_SEL(sel, "========== NM (VER-%d) ==========\n", RTK_NOISE_MONITOR_VERSION); ++ ++ _RTW_PRINT_SEL(sel, "%5s %3s %3s %10s", "Index", "CH", "BSS", "Noise(dBm)\n"); ++ ++ _rtw_bss_nums_count(adapter, hal_data->nm.bss_nums); ++ ++ for (ch_idx = 0; ch_idx < max_chan_nums; ch_idx++) { ++ ch_num = rtw_get_ch_num_by_idx(adapter, ch_idx); ++ _RTW_PRINT_SEL(sel, "%5d %3d %3d %10d\n", ++ ch_idx, ch_num, hal_data->nm.bss_nums[ch_idx], ++ hal_data->nm.noise[ch_idx]); ++ } ++} ++ ++void rtw_noise_measure(_adapter *adapter, u8 chan, u8 is_pause_dig, u8 igi_value, u32 max_time) ++{ ++ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); ++ struct dm_struct *phydm = &hal_data->odmpriv; ++ int chan_idx = -1; ++ s16 noise = 0; ++ ++ #ifdef DBG_NOISE_MONITOR ++ RTW_INFO("[NM] chan(%d)-PauseDIG:%s, IGIValue:0x%02x, max_time:%d (ms)\n", ++ chan, (is_pause_dig) ? "Y" : "N", igi_value, max_time); ++ #endif ++ ++ chan_idx = rtw_chset_search_ch(adapter_to_chset(adapter), chan); ++ if ((chan_idx == -1) || (chan_idx >= MAX_CHANNEL_NUM)) { ++ RTW_ERR("[NM] Get noise fail, can't get chan_idx(CH:%d)\n", chan); ++ return; ++ } ++ noise = odm_inband_noise_monitor(phydm, is_pause_dig, igi_value, max_time); /*dBm*/ ++ ++ hal_data->nm.noise[chan_idx] = noise; ++ ++ #ifdef DBG_NOISE_MONITOR ++ RTW_INFO("[NM] %s chan_%d, noise = %d (dBm)\n", __func__, chan, hal_data->nm.noise[chan_idx]); ++ ++ RTW_INFO("[NM] noise_a = %d, noise_b = %d noise_all:%d\n", ++ phydm->noise_level.noise[RF_PATH_A], ++ phydm->noise_level.noise[RF_PATH_B], ++ phydm->noise_level.noise_all); ++ #endif /*DBG_NOISE_MONITOR*/ ++} ++ ++s16 rtw_noise_query_by_chan_num(_adapter *adapter, u8 chan) ++{ ++ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); ++ s16 noise = 0; ++ int chan_idx = -1; ++ ++ chan_idx = rtw_chset_search_ch(adapter_to_chset(adapter), chan); ++ if ((chan_idx == -1) || (chan_idx >= MAX_CHANNEL_NUM)) { ++ RTW_ERR("[NM] Get noise fail, can't get chan_idx(CH:%d)\n", chan); ++ return noise; ++ } ++ noise = hal_data->nm.noise[chan_idx]; ++ ++ #ifdef DBG_NOISE_MONITOR ++ RTW_INFO("[NM] %s chan_%d, noise = %d (dBm)\n", __func__, chan, noise); ++ #endif/*DBG_NOISE_MONITOR*/ ++ return noise; ++} ++s16 rtw_noise_query_by_chan_idx(_adapter *adapter, u8 ch_idx) ++{ ++ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); ++ s16 noise = 0; ++ ++ if (ch_idx >= MAX_CHANNEL_NUM) { ++ RTW_ERR("[NM] %s ch_idx(%d) is invalid\n", __func__, ch_idx); ++ return noise; ++ } ++ noise = hal_data->nm.noise[ch_idx]; ++ ++ #ifdef DBG_NOISE_MONITOR ++ RTW_INFO("[NM] %s ch_idx %d, noise = %d (dBm)\n", __func__, ch_idx, noise); ++ #endif/*DBG_NOISE_MONITOR*/ ++ return noise; ++} ++ ++s16 rtw_noise_measure_curchan(_adapter *padapter) ++{ ++ s16 noise = 0; ++ u8 igi_value = 0x1E; ++ u32 max_time = 100;/* ms */ ++ u8 is_pause_dig = _TRUE; ++ u8 cur_chan = rtw_get_oper_ch(padapter); ++ ++#ifndef CONFIG_ALLOW_UNLINKED_NOISE_MONITOR ++ if (rtw_linked_check(padapter) == _FALSE) ++ return noise; ++#endif ++ ++ rtw_ps_deny(padapter, PS_DENY_IOCTL); ++ LeaveAllPowerSaveModeDirect(padapter); ++ rtw_noise_measure(padapter, cur_chan, is_pause_dig, igi_value, max_time); ++ noise = rtw_noise_query_by_chan_num(padapter, cur_chan); ++ rtw_ps_deny_cancel(padapter, PS_DENY_IOCTL); ++ ++ return noise; ++} ++#endif /*CONFIG_BACKGROUND_NOISE_MONITOR*/ ++ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_dm_acs.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_dm_acs.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/hal_dm_acs.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_dm_acs.h 2021-03-07 18:16:17.051955911 +0200 +@@ -0,0 +1,167 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++#ifndef __HAL_DM_ACS_H__ ++#define __HAL_DM_ACS_H__ ++#ifdef CONFIG_RTW_ACS ++#define RTK_ACS_VERSION 3 ++ ++#if (RTK_ACS_VERSION == 3) ++enum NHM_PID { ++ NHM_PID_ACS, ++ NHM_PID_IEEE_11K_HIGH, ++ NHM_PID_IEEE_11K_LOW, ++}; ++ ++#define init_clm_param(clm, app, lv, time) \ ++ do {\ ++ clm.clm_app = app;\ ++ clm.clm_lv = lv;\ ++ clm.mntr_time = time;\ ++ } while (0) ++ ++#define init_nhm_param(nhm, txon, cca, cnt_opt, app, lv, time) \ ++ do {\ ++ nhm.incld_txon = txon;\ ++ nhm.incld_cca = cca;\ ++ nhm.div_opt = cnt_opt;\ ++ nhm.nhm_app = app;\ ++ nhm.nhm_lv = lv;\ ++ nhm.mntr_time = time;\ ++ } while (0) ++ ++ ++#define init_acs_clm(clm, time) \ ++ init_clm_param(clm, CLM_ACS, CLM_LV_2, time) ++ ++#define init_acs_nhm(nhm, time) \ ++ init_nhm_param(nhm, NHM_EXCLUDE_TXON, NHM_EXCLUDE_CCA, NHM_CNT_ALL, NHM_ACS, NHM_LV_2, time) ++ ++#define init_11K_high_nhm(nhm, time) \ ++ init_nhm_param(nhm, NHM_EXCLUDE_TXON, NHM_EXCLUDE_CCA, NHM_CNT_ALL, IEEE_11K_HIGH, NHM_LV_2, time) ++ ++#define init_11K_low_nhm(nhm, time) \ ++ init_nhm_param(nhm, NHM_EXCLUDE_TXON, NHM_EXCLUDE_CCA, NHM_CNT_ALL, IEEE_11K_LOW, NHM_LV_2, time) ++ ++ ++#endif /*(RTK_ACS_VERSION == 3)*/ ++void rtw_acs_version_dump(void *sel, _adapter *adapter); ++extern void phydm_ccx_monitor_trigger(void *p_dm_void, u16 monitor_time); ++extern void phydm_ccx_monitor_result(void *p_dm_void); ++ ++#define GET_ACS_STATE(padapter) (ATOMIC_READ(&GET_HAL_DATA(padapter)->acs.state)) ++#define SET_ACS_STATE(padapter, set_state) (ATOMIC_SET(&GET_HAL_DATA(padapter)->acs.state, set_state)) ++#define IS_ACS_ENABLE(padapter) ((GET_ACS_STATE(padapter) == ACS_ENABLE) ? _TRUE : _FALSE) ++ ++enum ACS_STATE { ++ ACS_DISABLE, ++ ACS_ENABLE, ++}; ++ ++#define ACS_BW_20M BIT(0) ++#define ACS_BW_40M BIT(1) ++#define ACS_BW_80M BIT(2) ++#define ACS_BW_160M BIT(3) ++ ++struct auto_chan_sel { ++ ATOMIC_T state; ++ u8 trigger_ch; ++ bool triggered; ++ u8 clm_ratio[MAX_CHANNEL_NUM]; ++ u8 nhm_ratio[MAX_CHANNEL_NUM]; ++ #if (RTK_ACS_VERSION == 3) ++ u8 nhm[MAX_CHANNEL_NUM][NHM_RPT_NUM]; ++ #endif ++ u8 bss_nums[MAX_CHANNEL_NUM]; ++ u8 interference_time[MAX_CHANNEL_NUM]; ++ u8 cur_ch_clm_ratio; ++ u8 cur_ch_nhm_ratio; ++ u8 best_chan_5g; ++ u8 best_chan_24g; ++ ++ #if (RTK_ACS_VERSION == 3) ++ u8 trig_rst; ++ struct env_trig_rpt trig_rpt; ++ #endif ++ ++ #ifdef CONFIG_RTW_ACS_DBG ++ RT_SCAN_TYPE scan_type; ++ u16 scan_time; ++ u8 igi; ++ u8 bw; ++ #endif ++}; ++ ++#define rtw_acs_get_best_chan_24g(adapter) (GET_HAL_DATA(adapter)->acs.best_chan_24g) ++#define rtw_acs_get_best_chan_5g(adapter) (GET_HAL_DATA(adapter)->acs.best_chan_5g) ++ ++#ifdef CONFIG_RTW_ACS_DBG ++#define rtw_is_acs_passiv_scan(adapter) (((GET_HAL_DATA(adapter)->acs.scan_type) == SCAN_PASSIVE) ? _TRUE : _FALSE) ++ ++#define rtw_acs_get_adv_st(adapter) (GET_HAL_DATA(adapter)->acs.scan_time) ++#define rtw_is_acs_st_valid(adapter) ((GET_HAL_DATA(adapter)->acs.scan_time) ? _TRUE : _FALSE) ++ ++#define rtw_acs_get_adv_igi(adapter) (GET_HAL_DATA(adapter)->acs.igi) ++u8 rtw_is_acs_igi_valid(_adapter *adapter); ++ ++#define rtw_acs_get_adv_bw(adapter) (GET_HAL_DATA(adapter)->acs.bw) ++ ++void rtw_acs_adv_setting(_adapter *adapter, RT_SCAN_TYPE scan_type, u16 scan_time, u8 igi, u8 bw); ++void rtw_acs_adv_reset(_adapter *adapter); ++#endif ++ ++u8 rtw_acs_get_clm_ratio_by_ch_num(_adapter *adapter, u8 chan); ++u8 rtw_acs_get_clm_ratio_by_ch_idx(_adapter *adapter, u8 ch_idx); ++u8 rtw_acs_get_nhm_ratio_by_ch_num(_adapter *adapter, u8 chan); ++u8 rtw_acs_get_num_ratio_by_ch_idx(_adapter *adapter, u8 ch_idx); ++ ++void rtw_acs_reset(_adapter *adapter); ++void rtw_acs_trigger(_adapter *adapter, u16 scan_time_ms, u8 scan_chan, enum NHM_PID pid); ++void rtw_acs_get_rst(_adapter *adapter); ++void rtw_acs_select_best_chan(_adapter *adapter); ++void rtw_acs_info_dump(void *sel, _adapter *adapter); ++void rtw_acs_update_current_info(_adapter *adapter); ++void rtw_acs_chan_info_dump(void *sel, _adapter *adapter); ++void rtw_acs_current_info_dump(void *sel, _adapter *adapter); ++ ++void rtw_acs_start(_adapter *adapter); ++void rtw_acs_stop(_adapter *adapter); ++ ++#endif /*CONFIG_RTW_ACS*/ ++ ++#ifdef CONFIG_BACKGROUND_NOISE_MONITOR ++#define RTK_NOISE_MONITOR_VERSION 3 ++#define GET_NM_STATE(padapter) (ATOMIC_READ(&GET_HAL_DATA(padapter)->nm.state)) ++#define SET_NM_STATE(padapter, set_state) (ATOMIC_SET(&GET_HAL_DATA(padapter)->nm.state, set_state)) ++#define IS_NM_ENABLE(padapter) ((GET_NM_STATE(padapter) == NM_ENABLE) ? _TRUE : _FALSE) ++ ++enum NM_STATE { ++ NM_DISABLE, ++ NM_ENABLE, ++}; ++ ++struct noise_monitor { ++ ATOMIC_T state; ++ s16 noise[MAX_CHANNEL_NUM]; ++ u8 bss_nums[MAX_CHANNEL_NUM]; ++}; ++void rtw_nm_enable(_adapter *adapter); ++void rtw_nm_disable(_adapter *adapter); ++void rtw_noise_measure(_adapter *adapter, u8 chan, u8 is_pause_dig, u8 igi_value, u32 max_time); ++s16 rtw_noise_query_by_chan_num(_adapter *adapter, u8 chan); ++s16 rtw_noise_query_by_chan_idx(_adapter *adapter, u8 ch_idx); ++s16 rtw_noise_measure_curchan(_adapter *padapter); ++void rtw_noise_info_dump(void *sel, _adapter *adapter); ++#endif ++#endif /* __HAL_DM_ACS_H__ */ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_dm.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_dm.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/hal_dm.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_dm.c 2021-03-07 18:16:17.051955911 +0200 @@ -0,0 +1,1616 @@ +/****************************************************************************** + * @@ -149983,11 +147610,9 @@ index 000000000..c5fa43e30 + return; +} + -diff --git linux-5.8/3rdparty/rtl8812au/hal/hal_dm.h linux-5.8/3rdparty/rtl8812au/hal/hal_dm.h -new file mode 100644 -index 000000000..625021230 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/hal_dm.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_dm.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_dm.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/hal_dm.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_dm.h 2021-03-07 18:16:17.051955911 +0200 @@ -0,0 +1,111 @@ +/****************************************************************************** + * @@ -150100,746 +147725,9 @@ index 000000000..625021230 +#endif + +#endif /* __HAL_DM_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/hal/hal_dm_acs.c linux-5.8/3rdparty/rtl8812au/hal/hal_dm_acs.c -new file mode 100644 -index 000000000..49fc8a060 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/hal_dm_acs.c -@@ -0,0 +1,556 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2014 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+#include -+#include -+ -+ -+#if defined(CONFIG_RTW_ACS) || defined(CONFIG_BACKGROUND_NOISE_MONITOR) -+static void _rtw_bss_nums_count(_adapter *adapter, u8 *pbss_nums) -+{ -+ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); -+ _queue *queue = &(pmlmepriv->scanned_queue); -+ struct wlan_network *pnetwork = NULL; -+ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); -+ -+ _list *plist, *phead; -+ _irqL irqL; -+ int chan_idx = -1; -+ -+ if (pbss_nums == NULL) { -+ RTW_ERR("%s pbss_nums is null pointer\n", __func__); -+ return; -+ } -+ _rtw_memset(pbss_nums, 0, MAX_CHANNEL_NUM); -+ -+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); -+ phead = get_list_head(queue); -+ plist = get_next(phead); -+ while (1) { -+ if (rtw_end_of_queue_search(phead, plist) == _TRUE) -+ break; -+ -+ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); -+ if (!pnetwork) -+ break; -+ chan_idx = rtw_chset_search_ch(adapter_to_chset(adapter), pnetwork->network.Configuration.DSConfig); -+ if ((chan_idx == -1) || (chan_idx >= MAX_CHANNEL_NUM)) { -+ RTW_ERR("%s can't get chan_idx(CH:%d)\n", -+ __func__, pnetwork->network.Configuration.DSConfig); -+ chan_idx = 0; -+ } -+ /*if (pnetwork->network.Reserved[0] != BSS_TYPE_PROB_REQ)*/ -+ -+ pbss_nums[chan_idx]++; -+ -+ plist = get_next(plist); -+ } -+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); -+} -+ -+u8 rtw_get_ch_num_by_idx(_adapter *adapter, u8 idx) -+{ -+ struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter); -+ RT_CHANNEL_INFO *pch_set = rfctl->channel_set; -+ u8 max_chan_nums = rfctl->max_chan_nums; -+ -+ if (idx >= max_chan_nums) -+ return 0; -+ return pch_set[idx].ChannelNum; -+} -+#endif /*defined(CONFIG_RTW_ACS) || defined(CONFIG_BACKGROUND_NOISE_MONITOR)*/ -+ -+ -+#ifdef CONFIG_RTW_ACS -+void rtw_acs_version_dump(void *sel, _adapter *adapter) -+{ -+ _RTW_PRINT_SEL(sel, "RTK_ACS VER_%d\n", RTK_ACS_VERSION); -+} -+u8 rtw_phydm_clm_ratio(_adapter *adapter) -+{ -+ struct dm_struct *phydm = adapter_to_phydm(adapter); -+ -+ return phydm_cmn_info_query(phydm, (enum phydm_info_query) PHYDM_INFO_CLM_RATIO); -+} -+u8 rtw_phydm_nhm_ratio(_adapter *adapter) -+{ -+ struct dm_struct *phydm = adapter_to_phydm(adapter); -+ -+ return phydm_cmn_info_query(phydm, (enum phydm_info_query) PHYDM_INFO_NHM_RATIO); -+} -+void rtw_acs_reset(_adapter *adapter) -+{ -+ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); -+ struct auto_chan_sel *pacs = &hal_data->acs; -+ -+ _rtw_memset(pacs, 0, sizeof(struct auto_chan_sel)); -+ #ifdef CONFIG_RTW_ACS_DBG -+ rtw_acs_adv_reset(adapter); -+ #endif /*CONFIG_RTW_ACS_DBG*/ -+} -+ -+#ifdef CONFIG_RTW_ACS_DBG -+u8 rtw_is_acs_igi_valid(_adapter *adapter) -+{ -+ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); -+ struct auto_chan_sel *pacs = &hal_data->acs; -+ -+ if ((pacs->igi) && ((pacs->igi >= 0x1E) || (pacs->igi < 0x60))) -+ return _TRUE; -+ -+ return _FALSE; -+} -+void rtw_acs_adv_setting(_adapter *adapter, RT_SCAN_TYPE scan_type, u16 scan_time, u8 igi, u8 bw) -+{ -+ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); -+ struct auto_chan_sel *pacs = &hal_data->acs; -+ struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; -+ -+ pacs->scan_type = scan_type; -+ pacs->scan_time = scan_time; -+ pacs->igi = igi; -+ pacs->bw = bw; -+ RTW_INFO("[ACS] ADV setting - scan_type:%c, ch_ms:%d(ms), igi:0x%02x, bw:%d\n", -+ pacs->scan_type ? 'A' : 'P', pacs->scan_time, pacs->igi, pacs->bw); -+} -+void rtw_acs_adv_reset(_adapter *adapter) -+{ -+ rtw_acs_adv_setting(adapter, SCAN_ACTIVE, 0, 0, 0); -+} -+#endif /*CONFIG_RTW_ACS_DBG*/ -+ -+void rtw_acs_trigger(_adapter *adapter, u16 scan_time_ms, u8 scan_chan, enum NHM_PID pid) -+{ -+ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); -+ struct dm_struct *phydm = adapter_to_phydm(adapter); -+#if (RTK_ACS_VERSION == 3) -+ struct clm_para_info clm_para; -+ struct nhm_para_info nhm_para; -+ struct env_trig_rpt trig_rpt; -+ -+ scan_time_ms -= 10; -+ -+ init_acs_clm(clm_para, scan_time_ms); -+ -+ if (pid == NHM_PID_IEEE_11K_HIGH) -+ init_11K_high_nhm(nhm_para, scan_time_ms); -+ else if (pid == NHM_PID_IEEE_11K_LOW) -+ init_11K_low_nhm(nhm_para, scan_time_ms); -+ else -+ init_acs_nhm(nhm_para, scan_time_ms); -+ -+ hal_data->acs.trig_rst = phydm_env_mntr_trigger(phydm, &nhm_para, &clm_para, &trig_rpt); -+ if (hal_data->acs.trig_rst == (NHM_SUCCESS | CLM_SUCCESS)) { -+ hal_data->acs.trig_rpt.clm_rpt_stamp = trig_rpt.clm_rpt_stamp; -+ hal_data->acs.trig_rpt.nhm_rpt_stamp = trig_rpt.nhm_rpt_stamp; -+ /*RTW_INFO("[ACS] trigger success (rst = 0x%02x, clm_stamp:%d, nhm_stamp:%d)\n", -+ hal_data->acs.trig_rst, hal_data->acs.trig_rpt.clm_rpt_stamp, hal_data->acs.trig_rpt.nhm_rpt_stamp);*/ -+ } else -+ RTW_ERR("[ACS] trigger failed (rst = 0x%02x)\n", hal_data->acs.trig_rst); -+#else -+ phydm_ccx_monitor_trigger(phydm, scan_time_ms); -+#endif -+ -+ hal_data->acs.trigger_ch = scan_chan; -+ hal_data->acs.triggered = _TRUE; -+ -+ #ifdef CONFIG_RTW_ACS_DBG -+ RTW_INFO("[ACS] Trigger CH:%d, Times:%d\n", hal_data->acs.trigger_ch, scan_time_ms); -+ #endif -+} -+void rtw_acs_get_rst(_adapter *adapter) -+{ -+ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); -+ struct dm_struct *phydm = adapter_to_phydm(adapter); -+ int chan_idx = -1; -+ u8 cur_chan = hal_data->acs.trigger_ch; -+ -+ if (cur_chan == 0) -+ return; -+ -+ if (!hal_data->acs.triggered) -+ return; -+ -+ chan_idx = rtw_chset_search_ch(adapter_to_chset(adapter), cur_chan); -+ if ((chan_idx == -1) || (chan_idx >= MAX_CHANNEL_NUM)) { -+ RTW_ERR("[ACS] %s can't get chan_idx(CH:%d)\n", __func__, cur_chan); -+ return; -+ } -+#if (RTK_ACS_VERSION == 3) -+ if (!(hal_data->acs.trig_rst == (NHM_SUCCESS | CLM_SUCCESS))) { -+ RTW_ERR("[ACS] get_rst return, due to acs trigger failed\n"); -+ return; -+ } -+ -+ { -+ struct env_mntr_rpt rpt = {0}; -+ u8 rst; -+ -+ rst = phydm_env_mntr_result(phydm, &rpt); -+ if ((rst == (NHM_SUCCESS | CLM_SUCCESS)) && -+ (rpt.clm_rpt_stamp == hal_data->acs.trig_rpt.clm_rpt_stamp) && -+ (rpt.nhm_rpt_stamp == hal_data->acs.trig_rpt.nhm_rpt_stamp)){ -+ hal_data->acs.clm_ratio[chan_idx] = rpt.clm_ratio; -+ hal_data->acs.nhm_ratio[chan_idx] = rpt.nhm_ratio; -+ _rtw_memcpy(&hal_data->acs.nhm[chan_idx][0], rpt.nhm_result, NHM_RPT_NUM); -+ -+ /*RTW_INFO("[ACS] get_rst success (rst = 0x%02x, clm_stamp:%d:%d, nhm_stamp:%d:%d)\n", -+ rst, -+ hal_data->acs.trig_rpt.clm_rpt_stamp, rpt.clm_rpt_stamp, -+ hal_data->acs.trig_rpt.nhm_rpt_stamp, rpt.nhm_rpt_stamp);*/ -+ } else { -+ RTW_ERR("[ACS] get_rst failed (rst = 0x%02x, clm_stamp:%d:%d, nhm_stamp:%d:%d)\n", -+ rst, -+ hal_data->acs.trig_rpt.clm_rpt_stamp, rpt.clm_rpt_stamp, -+ hal_data->acs.trig_rpt.nhm_rpt_stamp, rpt.nhm_rpt_stamp); -+ } -+ } -+ -+#else -+ phydm_ccx_monitor_result(phydm); -+ -+ hal_data->acs.clm_ratio[chan_idx] = rtw_phydm_clm_ratio(adapter); -+ hal_data->acs.nhm_ratio[chan_idx] = rtw_phydm_nhm_ratio(adapter); -+#endif -+ hal_data->acs.triggered = _FALSE; -+ #ifdef CONFIG_RTW_ACS_DBG -+ RTW_INFO("[ACS] Result CH:%d, CLM:%d NHM:%d\n", -+ cur_chan, hal_data->acs.clm_ratio[chan_idx], hal_data->acs.nhm_ratio[chan_idx]); -+ #endif -+} -+ -+void _rtw_phydm_acs_select_best_chan(_adapter *adapter) -+{ -+ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); -+ struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter); -+ u8 ch_idx; -+ u8 ch_idx_24g = 0xFF, ch_idx_5g = 0xFF; -+ u8 min_itf_24g = 0xFF, min_itf_5g = 0xFF; -+ u8 *pbss_nums = hal_data->acs.bss_nums; -+ u8 *pclm_ratio = hal_data->acs.clm_ratio; -+ u8 *pnhm_ratio = hal_data->acs.nhm_ratio; -+ u8 *pinterference_time = hal_data->acs.interference_time; -+ u8 max_chan_nums = rfctl->max_chan_nums; -+ -+ for (ch_idx = 0; ch_idx < max_chan_nums; ch_idx++) { -+ if (pbss_nums[ch_idx]) -+ pinterference_time[ch_idx] = (pclm_ratio[ch_idx] / 2) + pnhm_ratio[ch_idx]; -+ else -+ pinterference_time[ch_idx] = pclm_ratio[ch_idx] + pnhm_ratio[ch_idx]; -+ -+ if (rtw_get_ch_num_by_idx(adapter, ch_idx) < 14) { -+ if (pinterference_time[ch_idx] < min_itf_24g) { -+ min_itf_24g = pinterference_time[ch_idx]; -+ ch_idx_24g = ch_idx; -+ } -+ } else { -+ if (pinterference_time[ch_idx] < min_itf_5g) { -+ min_itf_5g = pinterference_time[ch_idx]; -+ ch_idx_5g = ch_idx; -+ } -+ } -+ } -+ if (ch_idx_24g != 0xFF) -+ hal_data->acs.best_chan_24g = rtw_get_ch_num_by_idx(adapter, ch_idx_24g); -+ -+ if (ch_idx_5g != 0xFF) -+ hal_data->acs.best_chan_5g = rtw_get_ch_num_by_idx(adapter, ch_idx_5g); -+ -+ hal_data->acs.trigger_ch = 0; -+} -+ -+void rtw_acs_info_dump(void *sel, _adapter *adapter) -+{ -+ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); -+ struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter); -+ u8 max_chan_nums = rfctl->max_chan_nums; -+ u8 ch_idx, ch_num; -+ -+ _RTW_PRINT_SEL(sel, "========== ACS (VER-%d) ==========\n", RTK_ACS_VERSION); -+ _RTW_PRINT_SEL(sel, "Best 24G Channel:%d\n", hal_data->acs.best_chan_24g); -+ _RTW_PRINT_SEL(sel, "Best 5G Channel:%d\n\n", hal_data->acs.best_chan_5g); -+ -+ #ifdef CONFIG_RTW_ACS_DBG -+ _RTW_PRINT_SEL(sel, "Advanced setting - scan_type:%c, ch_ms:%d(ms), igi:0x%02x, bw:%d\n", -+ hal_data->acs.scan_type ? 'A' : 'P', hal_data->acs.scan_time, hal_data->acs.igi, hal_data->acs.bw); -+ -+ _RTW_PRINT_SEL(sel, "BW 20MHz\n"); -+ _RTW_PRINT_SEL(sel, "%5s %3s %3s %3s(%%) %3s(%%) %3s\n", -+ "Index", "CH", "BSS", "CLM", "NHM", "ITF"); -+ -+ for (ch_idx = 0; ch_idx < max_chan_nums; ch_idx++) { -+ ch_num = rtw_get_ch_num_by_idx(adapter, ch_idx); -+ _RTW_PRINT_SEL(sel, "%5d %3d %3d %6d %6d %3d\n", -+ ch_idx, ch_num, hal_data->acs.bss_nums[ch_idx], -+ hal_data->acs.clm_ratio[ch_idx], -+ hal_data->acs.nhm_ratio[ch_idx], -+ hal_data->acs.interference_time[ch_idx]); -+ } -+ #endif -+} -+void rtw_acs_select_best_chan(_adapter *adapter) -+{ -+ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); -+ -+ _rtw_bss_nums_count(adapter, hal_data->acs.bss_nums); -+ _rtw_phydm_acs_select_best_chan(adapter); -+ rtw_acs_info_dump(RTW_DBGDUMP, adapter); -+} -+ -+void rtw_acs_start(_adapter *adapter) -+{ -+ rtw_acs_reset(adapter); -+ if (GET_ACS_STATE(adapter) != ACS_ENABLE) -+ SET_ACS_STATE(adapter, ACS_ENABLE); -+} -+void rtw_acs_stop(_adapter *adapter) -+{ -+ SET_ACS_STATE(adapter, ACS_DISABLE); -+} -+ -+ -+u8 rtw_acs_get_clm_ratio_by_ch_num(_adapter *adapter, u8 chan) -+{ -+ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); -+ int chan_idx = -1; -+ -+ chan_idx = rtw_chset_search_ch(adapter_to_chset(adapter), chan); -+ if ((chan_idx == -1) || (chan_idx >= MAX_CHANNEL_NUM)) { -+ RTW_ERR("[ACS] Get CLM fail, can't get chan_idx(CH:%d)\n", chan); -+ return 0; -+ } -+ -+ return hal_data->acs.clm_ratio[chan_idx]; -+} -+u8 rtw_acs_get_clm_ratio_by_ch_idx(_adapter *adapter, u8 ch_idx) -+{ -+ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); -+ -+ if (ch_idx >= MAX_CHANNEL_NUM) { -+ RTW_ERR("%s [ACS] ch_idx(%d) is invalid\n", __func__, ch_idx); -+ return 0; -+ } -+ -+ return hal_data->acs.clm_ratio[ch_idx]; -+} -+u8 rtw_acs_get_nhm_ratio_by_ch_num(_adapter *adapter, u8 chan) -+{ -+ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); -+ int chan_idx = -1; -+ -+ chan_idx = rtw_chset_search_ch(adapter_to_chset(adapter), chan); -+ if ((chan_idx == -1) || (chan_idx >= MAX_CHANNEL_NUM)) { -+ RTW_ERR("[ACS] Get NHM fail, can't get chan_idx(CH:%d)\n", chan); -+ return 0; -+ } -+ -+ return hal_data->acs.nhm_ratio[chan_idx]; -+} -+u8 rtw_acs_get_num_ratio_by_ch_idx(_adapter *adapter, u8 ch_idx) -+{ -+ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); -+ -+ if (ch_idx >= MAX_CHANNEL_NUM) { -+ RTW_ERR("%s [ACS] ch_idx(%d) is invalid\n", __func__, ch_idx); -+ return 0; -+ } -+ -+ return hal_data->acs.nhm_ratio[ch_idx]; -+} -+void rtw_acs_chan_info_dump(void *sel, _adapter *adapter) -+{ -+ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); -+ struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter); -+ u8 max_chan_nums = rfctl->max_chan_nums; -+ u8 ch_idx, ch_num; -+ u8 utilization; -+ -+ _RTW_PRINT_SEL(sel, "BW 20MHz\n"); -+ _RTW_PRINT_SEL(sel, "%5s %3s %7s(%%) %12s(%%) %11s(%%) %9s(%%) %8s(%%)\n", -+ "Index", "CH", "Quality", "Availability", "Utilization", -+ "WIFI Util", "Interference Util"); -+ -+ for (ch_idx = 0; ch_idx < max_chan_nums; ch_idx++) { -+ ch_num = rtw_get_ch_num_by_idx(adapter, ch_idx); -+ utilization = hal_data->acs.clm_ratio[ch_idx] + hal_data->acs.nhm_ratio[ch_idx]; -+ _RTW_PRINT_SEL(sel, "%5d %3d %7d %12d %12d %12d %12d\n", -+ ch_idx, ch_num, -+ (100-hal_data->acs.interference_time[ch_idx]), -+ (100-utilization), -+ utilization, -+ hal_data->acs.clm_ratio[ch_idx], -+ hal_data->acs.nhm_ratio[ch_idx]); -+ } -+} -+void rtw_acs_current_info_dump(void *sel, _adapter *adapter) -+{ -+ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); -+ u8 ch, cen_ch, bw, offset; -+ -+ _RTW_PRINT_SEL(sel, "========== ACS (VER-%d) ==========\n", RTK_ACS_VERSION); -+ -+ ch = rtw_get_oper_ch(adapter); -+ bw = rtw_get_oper_bw(adapter); -+ offset = rtw_get_oper_choffset(adapter); -+ -+ _RTW_PRINT_SEL(sel, "Current Channel:%d\n", ch); -+ if ((bw == CHANNEL_WIDTH_80) ||(bw == CHANNEL_WIDTH_40)) { -+ cen_ch = rtw_get_center_ch(ch, bw, offset); -+ _RTW_PRINT_SEL(sel, "Center Channel:%d\n", cen_ch); -+ } -+ -+ _RTW_PRINT_SEL(sel, "Current BW %s\n", ch_width_str(bw)); -+ if (0) -+ _RTW_PRINT_SEL(sel, "Current IGI 0x%02x\n", rtw_phydm_get_cur_igi(adapter)); -+ _RTW_PRINT_SEL(sel, "CLM:%d, NHM:%d\n\n", -+ hal_data->acs.cur_ch_clm_ratio, hal_data->acs.cur_ch_nhm_ratio); -+} -+ -+void rtw_acs_update_current_info(_adapter *adapter) -+{ -+ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); -+ -+ hal_data->acs.cur_ch_clm_ratio = rtw_phydm_clm_ratio(adapter); -+ hal_data->acs.cur_ch_nhm_ratio = rtw_phydm_nhm_ratio(adapter); -+ -+ #ifdef CONFIG_RTW_ACS_DBG -+ rtw_acs_current_info_dump(RTW_DBGDUMP, adapter); -+ #endif -+} -+#endif /*CONFIG_RTW_ACS*/ -+ -+#ifdef CONFIG_BACKGROUND_NOISE_MONITOR -+void rtw_noise_monitor_version_dump(void *sel, _adapter *adapter) -+{ -+ _RTW_PRINT_SEL(sel, "RTK_NOISE_MONITOR VER_%d\n", RTK_NOISE_MONITOR_VERSION); -+} -+void rtw_nm_enable(_adapter *adapter) -+{ -+ SET_NM_STATE(adapter, NM_ENABLE); -+} -+void rtw_nm_disable(_adapter *adapter) -+{ -+ SET_NM_STATE(adapter, NM_DISABLE); -+} -+void rtw_noise_info_dump(void *sel, _adapter *adapter) -+{ -+ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); -+ struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter); -+ u8 max_chan_nums = rfctl->max_chan_nums; -+ u8 ch_idx, ch_num; -+ -+ _RTW_PRINT_SEL(sel, "========== NM (VER-%d) ==========\n", RTK_NOISE_MONITOR_VERSION); -+ -+ _RTW_PRINT_SEL(sel, "%5s %3s %3s %10s", "Index", "CH", "BSS", "Noise(dBm)\n"); -+ -+ _rtw_bss_nums_count(adapter, hal_data->nm.bss_nums); -+ -+ for (ch_idx = 0; ch_idx < max_chan_nums; ch_idx++) { -+ ch_num = rtw_get_ch_num_by_idx(adapter, ch_idx); -+ _RTW_PRINT_SEL(sel, "%5d %3d %3d %10d\n", -+ ch_idx, ch_num, hal_data->nm.bss_nums[ch_idx], -+ hal_data->nm.noise[ch_idx]); -+ } -+} -+ -+void rtw_noise_measure(_adapter *adapter, u8 chan, u8 is_pause_dig, u8 igi_value, u32 max_time) -+{ -+ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); -+ struct dm_struct *phydm = &hal_data->odmpriv; -+ int chan_idx = -1; -+ s16 noise = 0; -+ -+ #ifdef DBG_NOISE_MONITOR -+ RTW_INFO("[NM] chan(%d)-PauseDIG:%s, IGIValue:0x%02x, max_time:%d (ms)\n", -+ chan, (is_pause_dig) ? "Y" : "N", igi_value, max_time); -+ #endif -+ -+ chan_idx = rtw_chset_search_ch(adapter_to_chset(adapter), chan); -+ if ((chan_idx == -1) || (chan_idx >= MAX_CHANNEL_NUM)) { -+ RTW_ERR("[NM] Get noise fail, can't get chan_idx(CH:%d)\n", chan); -+ return; -+ } -+ noise = odm_inband_noise_monitor(phydm, is_pause_dig, igi_value, max_time); /*dBm*/ -+ -+ hal_data->nm.noise[chan_idx] = noise; -+ -+ #ifdef DBG_NOISE_MONITOR -+ RTW_INFO("[NM] %s chan_%d, noise = %d (dBm)\n", __func__, chan, hal_data->nm.noise[chan_idx]); -+ -+ RTW_INFO("[NM] noise_a = %d, noise_b = %d noise_all:%d\n", -+ phydm->noise_level.noise[RF_PATH_A], -+ phydm->noise_level.noise[RF_PATH_B], -+ phydm->noise_level.noise_all); -+ #endif /*DBG_NOISE_MONITOR*/ -+} -+ -+s16 rtw_noise_query_by_chan_num(_adapter *adapter, u8 chan) -+{ -+ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); -+ s16 noise = 0; -+ int chan_idx = -1; -+ -+ chan_idx = rtw_chset_search_ch(adapter_to_chset(adapter), chan); -+ if ((chan_idx == -1) || (chan_idx >= MAX_CHANNEL_NUM)) { -+ RTW_ERR("[NM] Get noise fail, can't get chan_idx(CH:%d)\n", chan); -+ return noise; -+ } -+ noise = hal_data->nm.noise[chan_idx]; -+ -+ #ifdef DBG_NOISE_MONITOR -+ RTW_INFO("[NM] %s chan_%d, noise = %d (dBm)\n", __func__, chan, noise); -+ #endif/*DBG_NOISE_MONITOR*/ -+ return noise; -+} -+s16 rtw_noise_query_by_chan_idx(_adapter *adapter, u8 ch_idx) -+{ -+ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); -+ s16 noise = 0; -+ -+ if (ch_idx >= MAX_CHANNEL_NUM) { -+ RTW_ERR("[NM] %s ch_idx(%d) is invalid\n", __func__, ch_idx); -+ return noise; -+ } -+ noise = hal_data->nm.noise[ch_idx]; -+ -+ #ifdef DBG_NOISE_MONITOR -+ RTW_INFO("[NM] %s ch_idx %d, noise = %d (dBm)\n", __func__, ch_idx, noise); -+ #endif/*DBG_NOISE_MONITOR*/ -+ return noise; -+} -+ -+s16 rtw_noise_measure_curchan(_adapter *padapter) -+{ -+ s16 noise = 0; -+ u8 igi_value = 0x1E; -+ u32 max_time = 100;/* ms */ -+ u8 is_pause_dig = _TRUE; -+ u8 cur_chan = rtw_get_oper_ch(padapter); -+ -+#ifndef CONFIG_ALLOW_UNLINKED_NOISE_MONITOR -+ if (rtw_linked_check(padapter) == _FALSE) -+ return noise; -+#endif -+ -+ rtw_ps_deny(padapter, PS_DENY_IOCTL); -+ LeaveAllPowerSaveModeDirect(padapter); -+ rtw_noise_measure(padapter, cur_chan, is_pause_dig, igi_value, max_time); -+ noise = rtw_noise_query_by_chan_num(padapter, cur_chan); -+ rtw_ps_deny_cancel(padapter, PS_DENY_IOCTL); -+ -+ return noise; -+} -+#endif /*CONFIG_BACKGROUND_NOISE_MONITOR*/ -+ -diff --git linux-5.8/3rdparty/rtl8812au/hal/hal_dm_acs.h linux-5.8/3rdparty/rtl8812au/hal/hal_dm_acs.h -new file mode 100644 -index 000000000..871c14487 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/hal_dm_acs.h -@@ -0,0 +1,167 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+#ifndef __HAL_DM_ACS_H__ -+#define __HAL_DM_ACS_H__ -+#ifdef CONFIG_RTW_ACS -+#define RTK_ACS_VERSION 3 -+ -+#if (RTK_ACS_VERSION == 3) -+enum NHM_PID { -+ NHM_PID_ACS, -+ NHM_PID_IEEE_11K_HIGH, -+ NHM_PID_IEEE_11K_LOW, -+}; -+ -+#define init_clm_param(clm, app, lv, time) \ -+ do {\ -+ clm.clm_app = app;\ -+ clm.clm_lv = lv;\ -+ clm.mntr_time = time;\ -+ } while (0) -+ -+#define init_nhm_param(nhm, txon, cca, cnt_opt, app, lv, time) \ -+ do {\ -+ nhm.incld_txon = txon;\ -+ nhm.incld_cca = cca;\ -+ nhm.div_opt = cnt_opt;\ -+ nhm.nhm_app = app;\ -+ nhm.nhm_lv = lv;\ -+ nhm.mntr_time = time;\ -+ } while (0) -+ -+ -+#define init_acs_clm(clm, time) \ -+ init_clm_param(clm, CLM_ACS, CLM_LV_2, time) -+ -+#define init_acs_nhm(nhm, time) \ -+ init_nhm_param(nhm, NHM_EXCLUDE_TXON, NHM_EXCLUDE_CCA, NHM_CNT_ALL, NHM_ACS, NHM_LV_2, time) -+ -+#define init_11K_high_nhm(nhm, time) \ -+ init_nhm_param(nhm, NHM_EXCLUDE_TXON, NHM_EXCLUDE_CCA, NHM_CNT_ALL, IEEE_11K_HIGH, NHM_LV_2, time) -+ -+#define init_11K_low_nhm(nhm, time) \ -+ init_nhm_param(nhm, NHM_EXCLUDE_TXON, NHM_EXCLUDE_CCA, NHM_CNT_ALL, IEEE_11K_LOW, NHM_LV_2, time) -+ -+ -+#endif /*(RTK_ACS_VERSION == 3)*/ -+void rtw_acs_version_dump(void *sel, _adapter *adapter); -+extern void phydm_ccx_monitor_trigger(void *p_dm_void, u16 monitor_time); -+extern void phydm_ccx_monitor_result(void *p_dm_void); -+ -+#define GET_ACS_STATE(padapter) (ATOMIC_READ(&GET_HAL_DATA(padapter)->acs.state)) -+#define SET_ACS_STATE(padapter, set_state) (ATOMIC_SET(&GET_HAL_DATA(padapter)->acs.state, set_state)) -+#define IS_ACS_ENABLE(padapter) ((GET_ACS_STATE(padapter) == ACS_ENABLE) ? _TRUE : _FALSE) -+ -+enum ACS_STATE { -+ ACS_DISABLE, -+ ACS_ENABLE, -+}; -+ -+#define ACS_BW_20M BIT(0) -+#define ACS_BW_40M BIT(1) -+#define ACS_BW_80M BIT(2) -+#define ACS_BW_160M BIT(3) -+ -+struct auto_chan_sel { -+ ATOMIC_T state; -+ u8 trigger_ch; -+ bool triggered; -+ u8 clm_ratio[MAX_CHANNEL_NUM]; -+ u8 nhm_ratio[MAX_CHANNEL_NUM]; -+ #if (RTK_ACS_VERSION == 3) -+ u8 nhm[MAX_CHANNEL_NUM][NHM_RPT_NUM]; -+ #endif -+ u8 bss_nums[MAX_CHANNEL_NUM]; -+ u8 interference_time[MAX_CHANNEL_NUM]; -+ u8 cur_ch_clm_ratio; -+ u8 cur_ch_nhm_ratio; -+ u8 best_chan_5g; -+ u8 best_chan_24g; -+ -+ #if (RTK_ACS_VERSION == 3) -+ u8 trig_rst; -+ struct env_trig_rpt trig_rpt; -+ #endif -+ -+ #ifdef CONFIG_RTW_ACS_DBG -+ RT_SCAN_TYPE scan_type; -+ u16 scan_time; -+ u8 igi; -+ u8 bw; -+ #endif -+}; -+ -+#define rtw_acs_get_best_chan_24g(adapter) (GET_HAL_DATA(adapter)->acs.best_chan_24g) -+#define rtw_acs_get_best_chan_5g(adapter) (GET_HAL_DATA(adapter)->acs.best_chan_5g) -+ -+#ifdef CONFIG_RTW_ACS_DBG -+#define rtw_is_acs_passiv_scan(adapter) (((GET_HAL_DATA(adapter)->acs.scan_type) == SCAN_PASSIVE) ? _TRUE : _FALSE) -+ -+#define rtw_acs_get_adv_st(adapter) (GET_HAL_DATA(adapter)->acs.scan_time) -+#define rtw_is_acs_st_valid(adapter) ((GET_HAL_DATA(adapter)->acs.scan_time) ? _TRUE : _FALSE) -+ -+#define rtw_acs_get_adv_igi(adapter) (GET_HAL_DATA(adapter)->acs.igi) -+u8 rtw_is_acs_igi_valid(_adapter *adapter); -+ -+#define rtw_acs_get_adv_bw(adapter) (GET_HAL_DATA(adapter)->acs.bw) -+ -+void rtw_acs_adv_setting(_adapter *adapter, RT_SCAN_TYPE scan_type, u16 scan_time, u8 igi, u8 bw); -+void rtw_acs_adv_reset(_adapter *adapter); -+#endif -+ -+u8 rtw_acs_get_clm_ratio_by_ch_num(_adapter *adapter, u8 chan); -+u8 rtw_acs_get_clm_ratio_by_ch_idx(_adapter *adapter, u8 ch_idx); -+u8 rtw_acs_get_nhm_ratio_by_ch_num(_adapter *adapter, u8 chan); -+u8 rtw_acs_get_num_ratio_by_ch_idx(_adapter *adapter, u8 ch_idx); -+ -+void rtw_acs_reset(_adapter *adapter); -+void rtw_acs_trigger(_adapter *adapter, u16 scan_time_ms, u8 scan_chan, enum NHM_PID pid); -+void rtw_acs_get_rst(_adapter *adapter); -+void rtw_acs_select_best_chan(_adapter *adapter); -+void rtw_acs_info_dump(void *sel, _adapter *adapter); -+void rtw_acs_update_current_info(_adapter *adapter); -+void rtw_acs_chan_info_dump(void *sel, _adapter *adapter); -+void rtw_acs_current_info_dump(void *sel, _adapter *adapter); -+ -+void rtw_acs_start(_adapter *adapter); -+void rtw_acs_stop(_adapter *adapter); -+ -+#endif /*CONFIG_RTW_ACS*/ -+ -+#ifdef CONFIG_BACKGROUND_NOISE_MONITOR -+#define RTK_NOISE_MONITOR_VERSION 3 -+#define GET_NM_STATE(padapter) (ATOMIC_READ(&GET_HAL_DATA(padapter)->nm.state)) -+#define SET_NM_STATE(padapter, set_state) (ATOMIC_SET(&GET_HAL_DATA(padapter)->nm.state, set_state)) -+#define IS_NM_ENABLE(padapter) ((GET_NM_STATE(padapter) == NM_ENABLE) ? _TRUE : _FALSE) -+ -+enum NM_STATE { -+ NM_DISABLE, -+ NM_ENABLE, -+}; -+ -+struct noise_monitor { -+ ATOMIC_T state; -+ s16 noise[MAX_CHANNEL_NUM]; -+ u8 bss_nums[MAX_CHANNEL_NUM]; -+}; -+void rtw_nm_enable(_adapter *adapter); -+void rtw_nm_disable(_adapter *adapter); -+void rtw_noise_measure(_adapter *adapter, u8 chan, u8 is_pause_dig, u8 igi_value, u32 max_time); -+s16 rtw_noise_query_by_chan_num(_adapter *adapter, u8 chan); -+s16 rtw_noise_query_by_chan_idx(_adapter *adapter, u8 ch_idx); -+s16 rtw_noise_measure_curchan(_adapter *padapter); -+void rtw_noise_info_dump(void *sel, _adapter *adapter); -+#endif -+#endif /* __HAL_DM_ACS_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/hal/hal_halmac.c linux-5.8/3rdparty/rtl8812au/hal/hal_halmac.c -new file mode 100644 -index 000000000..0b74ecb48 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/hal_halmac.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_halmac.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_halmac.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/hal_halmac.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_halmac.c 2021-03-07 18:16:17.052955958 +0200 @@ -0,0 +1,5555 @@ +/****************************************************************************** + * @@ -156396,11 +153284,9 @@ index 000000000..0b74ecb48 + +#endif /* RTW_BEAMFORMING_VERSION_2 */ +#endif /* CONFIG_BEAMFORMING */ -diff --git linux-5.8/3rdparty/rtl8812au/hal/hal_halmac.h linux-5.8/3rdparty/rtl8812au/hal/hal_halmac.h -new file mode 100644 -index 000000000..152a0e83a ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/hal_halmac.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_halmac.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_halmac.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/hal_halmac.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_halmac.h 2021-03-07 18:16:17.052955958 +0200 @@ -0,0 +1,245 @@ +/****************************************************************************** + * @@ -156647,11 +153533,9 @@ index 000000000..152a0e83a +#endif /* CONFIG_BEAMFORMING */ + +#endif /* _HAL_HALMAC_H_ */ -diff --git linux-5.8/3rdparty/rtl8812au/hal/hal_hci/hal_usb.c linux-5.8/3rdparty/rtl8812au/hal/hal_hci/hal_usb.c -new file mode 100644 -index 000000000..20dc07bdf ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/hal_hci/hal_usb.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_hci/hal_usb.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_hci/hal_usb.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/hal_hci/hal_usb.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_hci/hal_usb.c 2021-03-07 18:16:17.052955958 +0200 @@ -0,0 +1,564 @@ +/****************************************************************************** + * @@ -157217,11 +154101,9 @@ index 000000000..20dc07bdf +#endif + +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/hal_intf.c linux-5.8/3rdparty/rtl8812au/hal/hal_intf.c -new file mode 100644 -index 000000000..66a2954c5 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/hal_intf.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_intf.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_intf.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/hal_intf.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_intf.c 2021-03-07 18:16:17.052955958 +0200 @@ -0,0 +1,1716 @@ +/****************************************************************************** + * @@ -158939,11 +155821,9 @@ index 000000000..66a2954c5 +#endif + return ret; +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/hal_mcc.c linux-5.8/3rdparty/rtl8812au/hal/hal_mcc.c -new file mode 100644 -index 000000000..179d4d54b ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/hal_mcc.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_mcc.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_mcc.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/hal_mcc.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_mcc.c 2021-03-07 18:16:17.052955958 +0200 @@ -0,0 +1,3488 @@ +/****************************************************************************** + * @@ -162433,11 +159313,9 @@ index 000000000..179d4d54b +} + +#endif /* CONFIG_MCC_MODE */ -diff --git linux-5.8/3rdparty/rtl8812au/hal/hal_mp.c linux-5.8/3rdparty/rtl8812au/hal/hal_mp.c -new file mode 100644 -index 000000000..0f084c7e9 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/hal_mp.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_mp.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_mp.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/hal_mp.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_mp.c 2021-03-07 18:16:17.053956006 +0200 @@ -0,0 +1,2269 @@ +/****************************************************************************** + * @@ -163355,7 +160233,7 @@ index 000000000..0f084c7e9 + + phy_set_bb_reg(pAdapter, rCCAonSec_Jaguar, BIT1, 0x1); /*/ Disable CCA*/ + -+ for (StartPath; StartPath <= EndPath; StartPath++) { ++ for (; StartPath <= EndPath; StartPath++) { + phy_set_rf_reg(pAdapter, StartPath, RF_AC_Jaguar, 0xF0000, 0x2); /*/ Tx mode: RF0x00[19:16]=4'b0010 */ + phy_set_rf_reg(pAdapter, StartPath, RF_AC_Jaguar, 0x1F, 0x0); /*/ Lowest RF gain index: RF_0x0[4:0] = 0*/ + @@ -163393,7 +160271,7 @@ index 000000000..0f084c7e9 + EndPath = RF_PATH_D; + break; + } -+ for (StartPath; StartPath <= EndPath; StartPath++) ++ for (; StartPath <= EndPath; StartPath++) + phy_set_rf_reg(pAdapter, StartPath, lna_low_gain_3, BIT1, 0x0); /* RF LO disabled */ + + phy_set_bb_reg(pAdapter, rCCAonSec_Jaguar, BIT1, 0x0); /* Enable CCA*/ @@ -164708,11 +161586,9 @@ index 000000000..0f084c7e9 +} + +#endif /* CONFIG_MP_INCLUDE*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/hal_phy.c linux-5.8/3rdparty/rtl8812au/hal/hal_phy.c -new file mode 100644 -index 000000000..1504a73ba ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/hal_phy.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_phy.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_phy.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/hal_phy.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/hal_phy.c 2021-03-07 18:16:17.053956006 +0200 @@ -0,0 +1,257 @@ +/****************************************************************************** + * @@ -164971,11 +161847,198 @@ index 000000000..1504a73ba + +} /* PHY_RFShadowRead */ +#endif /*CONFIG_RF_SHADOW_RW*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/led/hal_led.c linux-5.8/3rdparty/rtl8812au/hal/led/hal_led.c -new file mode 100644 -index 000000000..033d23b4c ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/led/hal_led.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/HalPwrSeqCmd.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/HalPwrSeqCmd.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/HalPwrSeqCmd.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/HalPwrSeqCmd.c 2021-03-07 18:16:17.049955817 +0200 +@@ -0,0 +1,185 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++/*++ ++Copyright (c) Realtek Semiconductor Corp. All rights reserved. ++ ++Module Name: ++ HalPwrSeqCmd.c ++ ++Abstract: ++ Implement HW Power sequence configuration CMD handling routine for Realtek devices. ++ ++Major Change History: ++ When Who What ++ ---------- --------------- ------------------------------- ++ 2011-10-26 Lucas Modify to be compatible with SD4-CE driver. ++ 2011-07-07 Roger Create. ++ ++--*/ ++#include ++ ++ ++/* ++ * Description: ++ * This routine deal with the Power Configuration CMDs parsing for RTL8723/RTL8188E Series IC. ++ * ++ * Assumption: ++ * We should follow specific format which was released from HW SD. ++ * ++ * 2011.07.07, added by Roger. ++ * */ ++u8 HalPwrSeqCmdParsing( ++ PADAPTER padapter, ++ u8 CutVersion, ++ u8 FabVersion, ++ u8 InterfaceType, ++ WLAN_PWR_CFG PwrSeqCmd[]) ++{ ++ WLAN_PWR_CFG PwrCfgCmd = {0}; ++ u8 bPollingBit = _FALSE; ++ u8 bHWICSupport = _FALSE; ++ u32 AryIdx = 0; ++ u8 value = 0; ++ u32 offset = 0; ++ u8 flag = 0; ++ u32 pollingCount = 0; /* polling autoload done. */ ++ u32 maxPollingCnt = 5000; ++ ++ do { ++ PwrCfgCmd = PwrSeqCmd[AryIdx]; ++ ++ ++ /* 2 Only Handle the command whose FAB, CUT, and Interface are matched */ ++ if ((GET_PWR_CFG_FAB_MASK(PwrCfgCmd) & FabVersion) && ++ (GET_PWR_CFG_CUT_MASK(PwrCfgCmd) & CutVersion) && ++ (GET_PWR_CFG_INTF_MASK(PwrCfgCmd) & InterfaceType)) { ++ switch (GET_PWR_CFG_CMD(PwrCfgCmd)) { ++ case PWR_CMD_READ: ++ break; ++ ++ case PWR_CMD_WRITE: ++ offset = GET_PWR_CFG_OFFSET(PwrCfgCmd); ++ ++#ifdef CONFIG_SDIO_HCI ++ /* */ ++ /* We should deal with interface specific address mapping for some interfaces, e.g., SDIO interface */ ++ /* 2011.07.07. */ ++ /* */ ++ if (GET_PWR_CFG_BASE(PwrCfgCmd) == PWR_BASEADDR_SDIO) { ++ /* Read Back SDIO Local value */ ++ value = SdioLocalCmd52Read1Byte(padapter, offset); ++ ++ value &= ~(GET_PWR_CFG_MASK(PwrCfgCmd)); ++ value |= (GET_PWR_CFG_VALUE(PwrCfgCmd) & GET_PWR_CFG_MASK(PwrCfgCmd)); ++ ++ /* Write Back SDIO Local value */ ++ SdioLocalCmd52Write1Byte(padapter, offset, value); ++ } else ++#endif ++ { ++#ifdef CONFIG_GSPI_HCI ++ if (GET_PWR_CFG_BASE(PwrCfgCmd) == PWR_BASEADDR_SDIO) ++ offset = SPI_LOCAL_OFFSET | offset; ++#endif ++ /* Read the value from system register */ ++ value = rtw_read8(padapter, offset); ++ ++ value = value & (~(GET_PWR_CFG_MASK(PwrCfgCmd))); ++ value = value | (GET_PWR_CFG_VALUE(PwrCfgCmd) & GET_PWR_CFG_MASK(PwrCfgCmd)); ++ ++ /* Write the value back to sytem register */ ++ rtw_write8(padapter, offset, value); ++ } ++ break; ++ ++ case PWR_CMD_POLLING: ++ ++ bPollingBit = _FALSE; ++ offset = GET_PWR_CFG_OFFSET(PwrCfgCmd); ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_PWR_CMD, &bHWICSupport); ++ if (bHWICSupport && offset == 0x06) { ++ flag = 0; ++ maxPollingCnt = 100000; ++ } else ++ maxPollingCnt = 5000; ++ ++#ifdef CONFIG_GSPI_HCI ++ if (GET_PWR_CFG_BASE(PwrCfgCmd) == PWR_BASEADDR_SDIO) ++ offset = SPI_LOCAL_OFFSET | offset; ++#endif ++ do { ++#ifdef CONFIG_SDIO_HCI ++ if (GET_PWR_CFG_BASE(PwrCfgCmd) == PWR_BASEADDR_SDIO) ++ value = SdioLocalCmd52Read1Byte(padapter, offset); ++ else ++#endif ++ value = rtw_read8(padapter, offset); ++ ++ value = value & GET_PWR_CFG_MASK(PwrCfgCmd); ++ if (value == (GET_PWR_CFG_VALUE(PwrCfgCmd) & GET_PWR_CFG_MASK(PwrCfgCmd))) ++ bPollingBit = _TRUE; ++ else ++ rtw_udelay_os(10); ++ ++ if (pollingCount++ > maxPollingCnt) { ++ RTW_ERR("HalPwrSeqCmdParsing: Fail to polling Offset[%#x]=%02x\n", offset, value); ++ ++ /* For PCIE + USB package poll power bit timeout issue only modify 8821AE and 8723BE */ ++ if (bHWICSupport && offset == 0x06 && flag == 0) { ++ ++ RTW_ERR("[WARNING] PCIE polling(0x%X) timeout(%d), Toggle 0x04[3] and try again.\n", offset, maxPollingCnt); ++ if (IS_HARDWARE_TYPE_8723DE(padapter)) ++ PlatformEFIOWrite1Byte(padapter, 0x40, (PlatformEFIORead1Byte(padapter, 0x40)) & (~BIT3)); ++ ++ PlatformEFIOWrite1Byte(padapter, 0x04, PlatformEFIORead1Byte(padapter, 0x04) | BIT3); ++ PlatformEFIOWrite1Byte(padapter, 0x04, PlatformEFIORead1Byte(padapter, 0x04) & ~BIT3); ++ ++ if (IS_HARDWARE_TYPE_8723DE(padapter)) ++ PlatformEFIOWrite1Byte(padapter, 0x40, PlatformEFIORead1Byte(padapter, 0x40)|BIT3); ++ ++ /* Retry Polling Process one more time */ ++ pollingCount = 0; ++ flag = 1; ++ } else { ++ return _FALSE; ++ } ++ } ++ } while (!bPollingBit); ++ ++ break; ++ ++ case PWR_CMD_DELAY: ++ if (GET_PWR_CFG_VALUE(PwrCfgCmd) == PWRSEQ_DELAY_US) ++ rtw_udelay_os(GET_PWR_CFG_OFFSET(PwrCfgCmd)); ++ else ++ rtw_udelay_os(GET_PWR_CFG_OFFSET(PwrCfgCmd) * 1000); ++ break; ++ ++ case PWR_CMD_END: ++ /* When this command is parsed, end the process */ ++ return _TRUE; ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ AryIdx++;/* Add Array Index */ ++ } while (1); ++ ++ return _TRUE; ++} +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/led/hal_led.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/led/hal_led.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/led/hal_led.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/led/hal_led.c 2021-03-07 18:16:17.053956006 +0200 @@ -0,0 +1,254 @@ +/****************************************************************************** + * @@ -165231,11 +162294,9 @@ index 000000000..033d23b4c + +#endif /* CONFIG_RTW_LED */ + -diff --git linux-5.8/3rdparty/rtl8812au/hal/led/hal_usb_led.c linux-5.8/3rdparty/rtl8812au/hal/led/hal_usb_led.c -new file mode 100644 -index 000000000..80f7a393c ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/led/hal_usb_led.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/led/hal_usb_led.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/led/hal_usb_led.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/led/hal_usb_led.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/led/hal_usb_led.c 2021-03-07 18:16:17.053956006 +0200 @@ -0,0 +1,4291 @@ +/****************************************************************************** + * @@ -169528,11 +166589,9 @@ index 000000000..80f7a393c + ResetLedStatus(pLed); +} +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/ap_makefile.mk linux-5.8/3rdparty/rtl8812au/hal/phydm/ap_makefile.mk -new file mode 100644 -index 000000000..def4490a1 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/ap_makefile.mk +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/ap_makefile.mk linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/ap_makefile.mk +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/ap_makefile.mk 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/ap_makefile.mk 2021-03-07 18:16:17.053956006 +0200 @@ -0,0 +1,188 @@ + +_PHYDM_FILES :=\ @@ -169722,11 +166781,9 @@ index 000000000..def4490a1 + + + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halhwimg.h linux-5.8/3rdparty/rtl8812au/hal/phydm/halhwimg.h -new file mode 100644 -index 000000000..2ae2aaa18 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halhwimg.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halhwimg.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halhwimg.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halhwimg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halhwimg.h 2021-03-07 18:16:17.053956006 +0200 @@ -0,0 +1,96 @@ +/****************************************************************************** + * @@ -169824,11 +166881,9 @@ index 000000000..2ae2aaa18 +#endif + +#endif /* @__INC_HW_IMG_H */ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ap.c linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ap.c -new file mode 100644 -index 000000000..c4967e264 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ap.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ap.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ap.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ap.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ap.c 2021-03-07 18:16:17.053956006 +0200 @@ -0,0 +1,1359 @@ +/****************************************************************************** + * @@ -171189,11 +168244,9 @@ index 000000000..c4967e264 + odm_iq_calibrate(dm); +#endif +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ap.h linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ap.h -new file mode 100644 -index 000000000..0c1cbb815 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ap.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ap.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ap.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ap.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ap.h 2021-03-07 18:16:17.053956006 +0200 @@ -0,0 +1,139 @@ +/****************************************************************************** + * @@ -171334,11 +168387,9 @@ index 000000000..0c1cbb815 +void phydm_rf_watchdog(void *dm_void); + +#endif /*#ifndef __HALPHYRF_H__*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ce.c linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ce.c -new file mode 100644 -index 000000000..c8753e500 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ce.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ce.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ce.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ce.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ce.c 2021-03-07 18:16:17.054956052 +0200 @@ -0,0 +1,920 @@ +/****************************************************************************** + * @@ -172260,11 +169311,9 @@ index 000000000..c8753e500 +#endif +#endif +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ce.h linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ce.h -new file mode 100644 -index 000000000..f0c444687 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ce.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ce.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ce.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ce.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ce.h 2021-03-07 18:16:17.054956052 +0200 @@ -0,0 +1,114 @@ +/****************************************************************************** + * @@ -172380,11 +169429,9 @@ index 000000000..f0c444687 +void phydm_rf_watchdog(void *dm_void); + +#endif /*__HALPHYRF_H__*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_iot.c linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_iot.c -new file mode 100644 -index 000000000..8145fc9bc ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_iot.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_iot.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_iot.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_iot.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_iot.c 2021-03-07 18:16:17.054956052 +0200 @@ -0,0 +1,528 @@ +/****************************************************************************** + * @@ -172914,11 +169961,9 @@ index 000000000..8145fc9bc + + odm_txpowertracking_check(dm); +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_iot.h linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_iot.h -new file mode 100644 -index 000000000..7eba821be ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_iot.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_iot.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_iot.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_iot.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_iot.h 2021-03-07 18:16:17.054956052 +0200 @@ -0,0 +1,124 @@ +/****************************************************************************** + * @@ -173044,11 +170089,9 @@ index 000000000..7eba821be +void phydm_rf_watchdog(void *dm_void); + +#endif /*#ifndef __HALPHYRF_H__*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_win.c linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_win.c -new file mode 100644 -index 000000000..79702788a ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_win.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_win.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_win.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_win.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_win.c 2021-03-07 18:16:17.054956052 +0200 @@ -0,0 +1,841 @@ +/****************************************************************************** + * @@ -173891,11 +170934,9 @@ index 000000000..79702788a + odm_iq_calibrate(dm); +#endif +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_win.h linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_win.h -new file mode 100644 -index 000000000..873948d45 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_win.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_win.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_win.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_win.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_win.h 2021-03-07 18:16:17.054956052 +0200 @@ -0,0 +1,125 @@ +/****************************************************************************** + * @@ -174022,11 +171063,9 @@ index 000000000..873948d45 +void phydm_rf_watchdog(struct dm_struct *dm); + +#endif /*#ifndef __HALPHYRF_H__*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf.c linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf.c -new file mode 100644 -index 000000000..32fd1f3db ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf.c 2021-03-07 18:16:17.054956052 +0200 @@ -0,0 +1,2395 @@ +/****************************************************************************** + * @@ -176423,11 +173462,544 @@ index 000000000..32fd1f3db +#endif +} + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf.h linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf.h -new file mode 100644 -index 000000000..8a45aae32 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_debug.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_debug.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_debug.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_debug.c 2021-03-07 18:16:17.055956100 +0200 +@@ -0,0 +1,267 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, ++ * Hsinchu 300, Taiwan. ++ * ++ * Larry Finger ++ * ++ *****************************************************************************/ ++ ++/*@************************************************************ ++ * include files ++ * ************************************************************ ++ */ ++ ++#include "mp_precomp.h" ++#include "phydm_precomp.h" ++ ++void halrf_basic_profile(void *dm_void, u32 *_used, char *output, u32 *_out_len) ++{ ++#ifdef CONFIG_PHYDM_DEBUG_FUNCTION ++ struct dm_struct *dm = (struct dm_struct *)dm_void; ++ u32 used = *_used; ++ u32 out_len = *_out_len; ++ ++ /* HAL RF version List */ ++ PDM_SNPF(out_len, used, output + used, out_len - used, "%-35s\n", ++ "% HAL RF version %"); ++ PDM_SNPF(out_len, used, output + used, out_len - used, " %-35s: %s\n", ++ "Power Tracking", HALRF_POWRTRACKING_VER); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ " %-35s: %s %s\n", "IQK", ++ (dm->fw_offload_ability & PHYDM_RF_IQK_OFFLOAD) ? "FW" : ++ HALRF_IQK_VER, ++ (halrf_match_iqk_version(dm_void)) ? "(match)" : "(mismatch)"); ++ ++ PDM_SNPF(out_len, used, output + used, out_len - used, " %-35s: %s\n", ++ "LCK", HALRF_LCK_VER); ++ PDM_SNPF(out_len, used, output + used, out_len - used, " %-35s: %s\n", ++ "DPK", HALRF_DPK_VER); ++ PDM_SNPF(out_len, used, output + used, out_len - used, " %-35s: %s\n", ++ "KFREE", HALRF_KFREE_VER); ++ PDM_SNPF(out_len, used, output + used, out_len - used, " %-35s: %s\n", ++ "TX 2G Current Calibration", HALRF_PABIASK_VER); ++ PDM_SNPF(out_len, used, output + used, out_len - used, " %-35s: %s\n", ++ "RFK Init. Parameter", HALRF_RFK_INIT_VER); ++ ++ *_used = used; ++ *_out_len = out_len; ++#endif ++} ++ ++void halrf_debug_trace(void *dm_void, char input[][16], u32 *_used, ++ char *output, u32 *_out_len) ++{ ++ struct dm_struct *dm = (struct dm_struct *)dm_void; ++ struct _hal_rf_ *rf = &dm->rf_table; ++ u32 one = 1; ++ u32 used = *_used; ++ u32 out_len = *_out_len; ++ u32 rf_var[10] = {0}; ++ u8 i; ++ ++ for (i = 0; i < 5; i++) ++ if (input[i + 1]) ++ PHYDM_SSCANF(input[i + 2], DCMD_DECIMAL, &rf_var[i]); ++ ++ if (rf_var[0] == 100) { ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "\n[DBG MSG] RF Selection\n"); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "00. (( %s ))TX_PWR_TRACK\n", ++ ((rf->rf_dbg_comp & DBG_RF_TX_PWR_TRACK) ? ("V") : ++ ("."))); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "01. (( %s ))IQK\n", ++ ((rf->rf_dbg_comp & DBG_RF_IQK) ? ("V") : ("."))); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "02. (( %s ))LCK\n", ++ ((rf->rf_dbg_comp & DBG_RF_LCK) ? ("V") : ("."))); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "03. (( %s ))DPK\n", ++ ((rf->rf_dbg_comp & DBG_RF_DPK) ? ("V") : ("."))); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "04. (( %s ))TXGAPK\n", ++ ((rf->rf_dbg_comp & DBG_RF_TXGAPK) ? ("V") : ("."))); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "29. (( %s ))MP\n", ++ ((rf->rf_dbg_comp & DBG_RF_MP) ? ("V") : ("."))); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "30. (( %s ))TMP\n", ++ ((rf->rf_dbg_comp & DBG_RF_TMP) ? ("V") : ("."))); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "31. (( %s ))INIT\n", ++ ((rf->rf_dbg_comp & DBG_RF_INIT) ? ("V") : ("."))); ++ ++ } else if (rf_var[0] == 101) { ++ rf->rf_dbg_comp = 0; ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "Disable all DBG COMP\n"); ++ } else { ++ if (rf_var[1] == 1) /*enable*/ ++ rf->rf_dbg_comp |= (one << rf_var[0]); ++ else if (rf_var[1] == 2) /*disable*/ ++ rf->rf_dbg_comp &= ~(one << rf_var[0]); ++ } ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "\nCurr-RF_Dbg_Comp = 0x%x\n", rf->rf_dbg_comp); ++ ++ *_used = used; ++ *_out_len = out_len; ++} ++ ++struct halrf_command { ++ char name[16]; ++ u8 id; ++}; ++ ++enum halrf_CMD_ID { ++ HALRF_HELP, ++ HALRF_SUPPORTABILITY, ++ HALRF_DBG_COMP, ++ HALRF_PROFILE, ++ HALRF_IQK_INFO, ++ HALRF_IQK, ++ HALRF_IQK_DEBUG, ++ HAL_BAND_SHIFT, ++}; ++ ++struct halrf_command halrf_cmd_ary[] = { ++ {"-h", HALRF_HELP}, ++ {"ability", HALRF_SUPPORTABILITY}, ++ {"dbg", HALRF_DBG_COMP}, ++ {"profile", HALRF_PROFILE}, ++ {"iqk_info", HALRF_IQK_INFO}, ++ {"iqk", HALRF_IQK}, ++ {"iqk_dbg", HALRF_IQK_DEBUG}, ++ {"band_shift", HAL_BAND_SHIFT}, ++}; ++ ++void halrf_cmd_parser(void *dm_void, char input[][16], u32 *_used, char *output, ++ u32 *_out_len, u32 input_num) ++{ ++ struct dm_struct *dm = (struct dm_struct *)dm_void; ++#ifdef CONFIG_PHYDM_DEBUG_FUNCTION ++ u8 id = 0; ++ u32 rf_var[10] = {0}; ++ u32 i, input_idx = 0; ++ u32 halrf_ary_size = ++ sizeof(halrf_cmd_ary) / sizeof(struct halrf_command); ++ u32 used = *_used; ++ u32 out_len = *_out_len; ++ ++ /* Parsing Cmd ID */ ++ for (i = 0; i < halrf_ary_size; i++) { ++ if (strcmp(halrf_cmd_ary[i].name, input[1]) == 0) { ++ id = halrf_cmd_ary[i].id; ++ break; ++ } ++ } ++ ++ if (i == halrf_ary_size) { ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "RF Cmd not found\n"); ++ return; ++ } ++ ++ switch (id) { ++ case HALRF_HELP: ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "RF cmd ==>\n"); ++ ++ for (i = 0; i < halrf_ary_size - 1; i++) { ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ " %-5d: %s\n", i, halrf_cmd_ary[i + 1].name); ++ } ++ break; ++ case HALRF_SUPPORTABILITY: ++ halrf_support_ability_debug(dm, &input[0], &used, output, ++ &out_len); ++ break; ++ case HAL_BAND_SHIFT: ++ halrf_support_band_shift_debug(dm, &input[0], &used, output, ++ &out_len); ++ break; ++ case HALRF_DBG_COMP: ++ halrf_debug_trace(dm, &input[0], &used, output, &out_len); ++ break; ++ case HALRF_PROFILE: ++ halrf_basic_profile(dm, &used, output, &out_len); ++ break; ++ case HALRF_IQK_INFO: ++#if (RTL8822B_SUPPORT == 1 || RTL8821C_SUPPORT == 1) ++ halrf_iqk_info_dump(dm, &used, output, &out_len); ++#endif ++ break; ++ case HALRF_IQK: ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "TRX IQK Trigger\n"); ++ halrf_iqk_trigger(dm, false); ++#if (RTL8822B_SUPPORT == 1 || RTL8821C_SUPPORT == 1) ++ halrf_iqk_info_dump(dm, &used, output, &out_len); ++#endif ++ break; ++ case HALRF_IQK_DEBUG: ++ ++ for (i = 0; i < 5; i++) { ++ if (input[i + 1]) { ++ PHYDM_SSCANF(input[i + 2], DCMD_HEX, ++ &rf_var[i]); ++ input_idx++; ++ } ++ } ++ ++ if (input_idx >= 1) { ++#if (RTL8822B_SUPPORT == 1 || RTL8821C_SUPPORT == 1) ++ if (dm->support_ic_type & (ODM_RTL8822B | ODM_RTL8821C)) ++ halrf_iqk_debug(dm, (u32 *)rf_var, &used, ++ output, &out_len); ++#endif ++ } ++ break; ++ default: ++ break; ++ } ++ ++ *_used = used; ++ *_out_len = out_len; ++#endif ++} ++ ++void halrf_init_debug_setting(void *dm_void) ++{ ++ struct dm_struct *dm = (struct dm_struct *)dm_void; ++ struct _hal_rf_ *rf = &dm->rf_table; ++ ++ rf->rf_dbg_comp = ++#if DBG ++#if 0 ++ /*DBG_RF_TX_PWR_TRACK |*/ ++ /*DBG_RF_IQK | */ ++ /*DBG_RF_LCK | */ ++ /*DBG_RF_DPK | */ ++ /*DBG_RF_DACK | */ ++ /*DBG_RF_TXGAPK | */ ++ /*DBG_RF_MP | */ ++ /*DBG_RF_TMP | */ ++ /*DBG_RF_INIT | */ ++#endif ++#endif ++ 0; ++} +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_debug.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_debug.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_debug.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_debug.h 2021-03-07 18:16:17.055956100 +0200 +@@ -0,0 +1,123 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, ++ * Hsinchu 300, Taiwan. ++ * ++ * Larry Finger ++ * ++ *****************************************************************************/ ++ ++#ifndef __HALRF_DEBUG_H__ ++#define __HALRF_DEBUG_H__ ++ ++/*@============================================================*/ ++/*@include files*/ ++/*@============================================================*/ ++ ++/*@============================================================*/ ++/*@Definition */ ++/*@============================================================*/ ++ ++#if DBG ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_AP) ++#define RF_DBG(dm, comp, fmt, args...) \ ++ do { \ ++ if ((comp) & dm->rf_table.rf_dbg_comp) { \ ++ pr_debug("[RF] "); \ ++ RT_PRINTK(fmt, ##args); \ ++ } \ ++ } while (0) ++ ++#elif (DM_ODM_SUPPORT_TYPE == ODM_WIN) ++ ++static __inline void RF_DBG(PDM_ODM_T dm, int comp, char *fmt, ...) ++{ ++ RT_STATUS rt_status; ++ va_list args; ++ char buf[PRINT_MAX_SIZE] = {0}; ++ ++ if ((comp & dm->rf_table.rf_dbg_comp) == 0) ++ return; ++ ++ if (fmt == NULL) ++ return; ++ ++ va_start(args, fmt); ++ rt_status = (RT_STATUS)RtlStringCbVPrintfA(buf, PRINT_MAX_SIZE, fmt, args); ++ va_end(args); ++ ++ if (rt_status != RT_STATUS_SUCCESS) { ++ DbgPrint("Failed (%d) to print message to buffer\n", rt_status); ++ return; ++ } ++ ++ DbgPrint("[RF] %s", buf); ++} ++ ++#elif (DM_ODM_SUPPORT_TYPE == ODM_IOT) ++ ++#define RF_DBG(dm, comp, fmt, args...) \ ++ do { \ ++ if ((comp) & dm->rf_table.rf_dbg_comp) { \ ++ RT_DEBUG(COMP_PHYDM, DBG_DMESG, "[RF] " fmt, ##args); \ ++ } \ ++ } while (0) ++ ++#else ++#define RF_DBG(dm, comp, fmt, args...) \ ++ do { \ ++ struct dm_struct *__dm = dm; \ ++ if ((comp) & __dm->rf_table.rf_dbg_comp) { \ ++ RT_TRACE(((struct rtl_priv *)__dm->adapter), \ ++ COMP_PHYDM, DBG_DMESG, "[RF] " fmt, ##args); \ ++ } \ ++ } while (0) ++#endif ++ ++#else /*#if DBG*/ ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) ++static __inline void RF_DBG(struct dm_struct *dm, int comp, char *fmt, ...) ++{ ++} ++#else ++#define RF_DBG(dm, comp, fmt, args...) ++#endif ++ ++#endif /*#if DBG*/ ++ ++/*@============================================================*/ ++/*@ enumeration */ ++/*@============================================================*/ ++ ++/*@============================================================*/ ++/*@ structure */ ++/*@============================================================*/ ++ ++/*@============================================================*/ ++/*@ function prototype */ ++/*@============================================================*/ ++ ++void halrf_cmd_parser(void *dm_void, char input[][16], u32 *_used, char *output, ++ u32 *_out_len, u32 input_num); ++ ++void halrf_init_debug_setting(void *dm_void); ++ ++#endif /*__HALRF_H__*/ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_dpk.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_dpk.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_dpk.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_dpk.h 2021-03-07 18:16:17.055956100 +0200 +@@ -0,0 +1,86 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, ++ * Hsinchu 300, Taiwan. ++ * ++ * Larry Finger ++ * ++ *****************************************************************************/ ++ ++#ifndef __HALRF_DPK_H__ ++#define __HALRF_DPK_H__ ++ ++/*@--------------------------Define Parameters-------------------------------*/ ++#define GAIN_LOSS 1 ++#define DO_DPK 2 ++#define DPK_ON 3 ++#define DPK_LOK 4 ++#define DPK_TXK 5 ++ ++#define DAGC 4 ++#define LOSS_CHK 0 ++#define GAIN_CHK 1 ++#define PAS_READ 2 ++#define AVG_THERMAL_NUM 8 ++#define AVG_THERMAL_NUM_DPK 8 ++#define THERMAL_DPK_AVG_NUM 4 ++ ++/*@---------------------------End Define Parameters---------------------------*/ ++ ++struct dm_dpk_info { ++ ++ boolean is_dpk_enable; ++ boolean is_dpk_pwr_on; ++ boolean is_dpk_by_channel; ++ u16 dpk_path_ok; ++ /*@BIT(15)~BIT(12) : 5G reserved, BIT(11)~BIT(8) 5G_S3~5G_S0*/ ++ /*@BIT(7)~BIT(4) : 2G reserved, BIT(3)~BIT(0) 2G_S3~2G_S0*/ ++ u8 thermal_dpk; ++ u8 thermal_dpk_avg[AVG_THERMAL_NUM_DPK]; ++ u8 thermal_dpk_avg_index; ++ ++#if (RTL8822C_SUPPORT == 1) ++ u8 result[2][1]; /*path/group*/ ++ u8 tx_agc[2][1]; /*path/group*/ ++ u32 coef[2][1][20]; /*path/group/MDPD coefficient*/ ++#endif ++ ++#if (RTL8198F_SUPPORT == 1 || RTL8192F_SUPPORT == 1 || RTL8197F_SUPPORT == 1) ++ /*2G DPK data*/ ++ u8 dpk_result[4][3]; /*path/group*/ ++ u8 pwsf_2g[4][3]; /*path/group*/ ++ u32 lut_2g_even[4][3][64]; /*path/group/LUT data*/ ++ u32 lut_2g_odd[4][3][64]; /*path/group/LUT data*/ ++#endif ++ ++#if (RTL8195B_SUPPORT == 1) ++ /*2G DPK data*/ ++ u8 dpk_2g_result[1][3]; /*path/group*/ ++ u8 pwsf_2g[1][3]; /*path/group*/ ++ u32 lut_2g_even[1][3][16]; /*path/group/LUT data*/ ++ u32 lut_2g_odd[1][3][16]; /*path/group/LUT data*/ ++ /*5G DPK data*/ ++ u8 dpk_5g_result[1][6]; /*path/group*/ ++ u8 pwsf_5g[1][6]; /*path/group*/ ++ u32 lut_5g_even[1][6][16]; /*path/group/LUT data*/ ++ u32 lut_5g_odd[1][6][16]; /*path/group/LUT data*/ ++#endif ++}; ++ ++#endif /*__HALRF_DPK_H__*/ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_features.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_features.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_features.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_features.h 2021-03-07 18:16:17.055956100 +0200 +@@ -0,0 +1,43 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, ++ * Hsinchu 300, Taiwan. ++ * ++ * Larry Finger ++ * ++ *****************************************************************************/ ++ ++#ifndef __HALRF_FEATURES_H__ ++#define __HALRF_FEATURES_H__ ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) ++ ++#define CONFIG_HALRF_POWERTRACKING 1 ++ ++#elif (DM_ODM_SUPPORT_TYPE == ODM_AP) ++ ++#define CONFIG_HALRF_POWERTRACKING 1 ++ ++#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ ++#define CONFIG_HALRF_POWERTRACKING 1 ++ ++#endif ++ ++#endif /*#ifndef __HALRF_FEATURES_H__*/ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf.h 2021-03-07 18:16:17.054956052 +0200 @@ -0,0 +1,573 @@ +/****************************************************************************** + * @@ -177002,554 +174574,9 @@ index 000000000..8a45aae32 +u32 halrf_query_tssi_value(void *dm_void); + +#endif /*__HALRF_H__*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_debug.c linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_debug.c -new file mode 100644 -index 000000000..85a7cb22b ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_debug.c -@@ -0,0 +1,267 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * The full GNU General Public License is included in this distribution in the -+ * file called LICENSE. -+ * -+ * Contact Information: -+ * wlanfae -+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, -+ * Hsinchu 300, Taiwan. -+ * -+ * Larry Finger -+ * -+ *****************************************************************************/ -+ -+/*@************************************************************ -+ * include files -+ * ************************************************************ -+ */ -+ -+#include "mp_precomp.h" -+#include "phydm_precomp.h" -+ -+void halrf_basic_profile(void *dm_void, u32 *_used, char *output, u32 *_out_len) -+{ -+#ifdef CONFIG_PHYDM_DEBUG_FUNCTION -+ struct dm_struct *dm = (struct dm_struct *)dm_void; -+ u32 used = *_used; -+ u32 out_len = *_out_len; -+ -+ /* HAL RF version List */ -+ PDM_SNPF(out_len, used, output + used, out_len - used, "%-35s\n", -+ "% HAL RF version %"); -+ PDM_SNPF(out_len, used, output + used, out_len - used, " %-35s: %s\n", -+ "Power Tracking", HALRF_POWRTRACKING_VER); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ " %-35s: %s %s\n", "IQK", -+ (dm->fw_offload_ability & PHYDM_RF_IQK_OFFLOAD) ? "FW" : -+ HALRF_IQK_VER, -+ (halrf_match_iqk_version(dm_void)) ? "(match)" : "(mismatch)"); -+ -+ PDM_SNPF(out_len, used, output + used, out_len - used, " %-35s: %s\n", -+ "LCK", HALRF_LCK_VER); -+ PDM_SNPF(out_len, used, output + used, out_len - used, " %-35s: %s\n", -+ "DPK", HALRF_DPK_VER); -+ PDM_SNPF(out_len, used, output + used, out_len - used, " %-35s: %s\n", -+ "KFREE", HALRF_KFREE_VER); -+ PDM_SNPF(out_len, used, output + used, out_len - used, " %-35s: %s\n", -+ "TX 2G Current Calibration", HALRF_PABIASK_VER); -+ PDM_SNPF(out_len, used, output + used, out_len - used, " %-35s: %s\n", -+ "RFK Init. Parameter", HALRF_RFK_INIT_VER); -+ -+ *_used = used; -+ *_out_len = out_len; -+#endif -+} -+ -+void halrf_debug_trace(void *dm_void, char input[][16], u32 *_used, -+ char *output, u32 *_out_len) -+{ -+ struct dm_struct *dm = (struct dm_struct *)dm_void; -+ struct _hal_rf_ *rf = &dm->rf_table; -+ u32 one = 1; -+ u32 used = *_used; -+ u32 out_len = *_out_len; -+ u32 rf_var[10] = {0}; -+ u8 i; -+ -+ for (i = 0; i < 5; i++) -+ if (input[i + 1]) -+ PHYDM_SSCANF(input[i + 2], DCMD_DECIMAL, &rf_var[i]); -+ -+ if (rf_var[0] == 100) { -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "\n[DBG MSG] RF Selection\n"); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "00. (( %s ))TX_PWR_TRACK\n", -+ ((rf->rf_dbg_comp & DBG_RF_TX_PWR_TRACK) ? ("V") : -+ ("."))); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "01. (( %s ))IQK\n", -+ ((rf->rf_dbg_comp & DBG_RF_IQK) ? ("V") : ("."))); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "02. (( %s ))LCK\n", -+ ((rf->rf_dbg_comp & DBG_RF_LCK) ? ("V") : ("."))); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "03. (( %s ))DPK\n", -+ ((rf->rf_dbg_comp & DBG_RF_DPK) ? ("V") : ("."))); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "04. (( %s ))TXGAPK\n", -+ ((rf->rf_dbg_comp & DBG_RF_TXGAPK) ? ("V") : ("."))); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "29. (( %s ))MP\n", -+ ((rf->rf_dbg_comp & DBG_RF_MP) ? ("V") : ("."))); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "30. (( %s ))TMP\n", -+ ((rf->rf_dbg_comp & DBG_RF_TMP) ? ("V") : ("."))); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "31. (( %s ))INIT\n", -+ ((rf->rf_dbg_comp & DBG_RF_INIT) ? ("V") : ("."))); -+ -+ } else if (rf_var[0] == 101) { -+ rf->rf_dbg_comp = 0; -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "Disable all DBG COMP\n"); -+ } else { -+ if (rf_var[1] == 1) /*enable*/ -+ rf->rf_dbg_comp |= (one << rf_var[0]); -+ else if (rf_var[1] == 2) /*disable*/ -+ rf->rf_dbg_comp &= ~(one << rf_var[0]); -+ } -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "\nCurr-RF_Dbg_Comp = 0x%x\n", rf->rf_dbg_comp); -+ -+ *_used = used; -+ *_out_len = out_len; -+} -+ -+struct halrf_command { -+ char name[16]; -+ u8 id; -+}; -+ -+enum halrf_CMD_ID { -+ HALRF_HELP, -+ HALRF_SUPPORTABILITY, -+ HALRF_DBG_COMP, -+ HALRF_PROFILE, -+ HALRF_IQK_INFO, -+ HALRF_IQK, -+ HALRF_IQK_DEBUG, -+ HAL_BAND_SHIFT, -+}; -+ -+struct halrf_command halrf_cmd_ary[] = { -+ {"-h", HALRF_HELP}, -+ {"ability", HALRF_SUPPORTABILITY}, -+ {"dbg", HALRF_DBG_COMP}, -+ {"profile", HALRF_PROFILE}, -+ {"iqk_info", HALRF_IQK_INFO}, -+ {"iqk", HALRF_IQK}, -+ {"iqk_dbg", HALRF_IQK_DEBUG}, -+ {"band_shift", HAL_BAND_SHIFT}, -+}; -+ -+void halrf_cmd_parser(void *dm_void, char input[][16], u32 *_used, char *output, -+ u32 *_out_len, u32 input_num) -+{ -+ struct dm_struct *dm = (struct dm_struct *)dm_void; -+#ifdef CONFIG_PHYDM_DEBUG_FUNCTION -+ u8 id = 0; -+ u32 rf_var[10] = {0}; -+ u32 i, input_idx = 0; -+ u32 halrf_ary_size = -+ sizeof(halrf_cmd_ary) / sizeof(struct halrf_command); -+ u32 used = *_used; -+ u32 out_len = *_out_len; -+ -+ /* Parsing Cmd ID */ -+ for (i = 0; i < halrf_ary_size; i++) { -+ if (strcmp(halrf_cmd_ary[i].name, input[1]) == 0) { -+ id = halrf_cmd_ary[i].id; -+ break; -+ } -+ } -+ -+ if (i == halrf_ary_size) { -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "RF Cmd not found\n"); -+ return; -+ } -+ -+ switch (id) { -+ case HALRF_HELP: -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "RF cmd ==>\n"); -+ -+ for (i = 0; i < halrf_ary_size - 1; i++) { -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ " %-5d: %s\n", i, halrf_cmd_ary[i + 1].name); -+ } -+ break; -+ case HALRF_SUPPORTABILITY: -+ halrf_support_ability_debug(dm, &input[0], &used, output, -+ &out_len); -+ break; -+ case HAL_BAND_SHIFT: -+ halrf_support_band_shift_debug(dm, &input[0], &used, output, -+ &out_len); -+ break; -+ case HALRF_DBG_COMP: -+ halrf_debug_trace(dm, &input[0], &used, output, &out_len); -+ break; -+ case HALRF_PROFILE: -+ halrf_basic_profile(dm, &used, output, &out_len); -+ break; -+ case HALRF_IQK_INFO: -+#if (RTL8822B_SUPPORT == 1 || RTL8821C_SUPPORT == 1) -+ halrf_iqk_info_dump(dm, &used, output, &out_len); -+#endif -+ break; -+ case HALRF_IQK: -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "TRX IQK Trigger\n"); -+ halrf_iqk_trigger(dm, false); -+#if (RTL8822B_SUPPORT == 1 || RTL8821C_SUPPORT == 1) -+ halrf_iqk_info_dump(dm, &used, output, &out_len); -+#endif -+ break; -+ case HALRF_IQK_DEBUG: -+ -+ for (i = 0; i < 5; i++) { -+ if (input[i + 1]) { -+ PHYDM_SSCANF(input[i + 2], DCMD_HEX, -+ &rf_var[i]); -+ input_idx++; -+ } -+ } -+ -+ if (input_idx >= 1) { -+#if (RTL8822B_SUPPORT == 1 || RTL8821C_SUPPORT == 1) -+ if (dm->support_ic_type & (ODM_RTL8822B | ODM_RTL8821C)) -+ halrf_iqk_debug(dm, (u32 *)rf_var, &used, -+ output, &out_len); -+#endif -+ } -+ break; -+ default: -+ break; -+ } -+ -+ *_used = used; -+ *_out_len = out_len; -+#endif -+} -+ -+void halrf_init_debug_setting(void *dm_void) -+{ -+ struct dm_struct *dm = (struct dm_struct *)dm_void; -+ struct _hal_rf_ *rf = &dm->rf_table; -+ -+ rf->rf_dbg_comp = -+#if DBG -+#if 0 -+ /*DBG_RF_TX_PWR_TRACK |*/ -+ /*DBG_RF_IQK | */ -+ /*DBG_RF_LCK | */ -+ /*DBG_RF_DPK | */ -+ /*DBG_RF_DACK | */ -+ /*DBG_RF_TXGAPK | */ -+ /*DBG_RF_MP | */ -+ /*DBG_RF_TMP | */ -+ /*DBG_RF_INIT | */ -+#endif -+#endif -+ 0; -+} -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_debug.h linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_debug.h -new file mode 100644 -index 000000000..ff1ff96d2 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_debug.h -@@ -0,0 +1,123 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * The full GNU General Public License is included in this distribution in the -+ * file called LICENSE. -+ * -+ * Contact Information: -+ * wlanfae -+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, -+ * Hsinchu 300, Taiwan. -+ * -+ * Larry Finger -+ * -+ *****************************************************************************/ -+ -+#ifndef __HALRF_DEBUG_H__ -+#define __HALRF_DEBUG_H__ -+ -+/*@============================================================*/ -+/*@include files*/ -+/*@============================================================*/ -+ -+/*@============================================================*/ -+/*@Definition */ -+/*@============================================================*/ -+ -+#if DBG -+ -+#if (DM_ODM_SUPPORT_TYPE == ODM_AP) -+#define RF_DBG(dm, comp, fmt, args...) \ -+ do { \ -+ if ((comp) & dm->rf_table.rf_dbg_comp) { \ -+ pr_debug("[RF] "); \ -+ RT_PRINTK(fmt, ##args); \ -+ } \ -+ } while (0) -+ -+#elif (DM_ODM_SUPPORT_TYPE == ODM_WIN) -+ -+static __inline void RF_DBG(PDM_ODM_T dm, int comp, char *fmt, ...) -+{ -+ RT_STATUS rt_status; -+ va_list args; -+ char buf[PRINT_MAX_SIZE] = {0}; -+ -+ if ((comp & dm->rf_table.rf_dbg_comp) == 0) -+ return; -+ -+ if (fmt == NULL) -+ return; -+ -+ va_start(args, fmt); -+ rt_status = (RT_STATUS)RtlStringCbVPrintfA(buf, PRINT_MAX_SIZE, fmt, args); -+ va_end(args); -+ -+ if (rt_status != RT_STATUS_SUCCESS) { -+ DbgPrint("Failed (%d) to print message to buffer\n", rt_status); -+ return; -+ } -+ -+ DbgPrint("[RF] %s", buf); -+} -+ -+#elif (DM_ODM_SUPPORT_TYPE == ODM_IOT) -+ -+#define RF_DBG(dm, comp, fmt, args...) \ -+ do { \ -+ if ((comp) & dm->rf_table.rf_dbg_comp) { \ -+ RT_DEBUG(COMP_PHYDM, DBG_DMESG, "[RF] " fmt, ##args); \ -+ } \ -+ } while (0) -+ -+#else -+#define RF_DBG(dm, comp, fmt, args...) \ -+ do { \ -+ struct dm_struct *__dm = dm; \ -+ if ((comp) & __dm->rf_table.rf_dbg_comp) { \ -+ RT_TRACE(((struct rtl_priv *)__dm->adapter), \ -+ COMP_PHYDM, DBG_DMESG, "[RF] " fmt, ##args); \ -+ } \ -+ } while (0) -+#endif -+ -+#else /*#if DBG*/ -+ -+#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) -+static __inline void RF_DBG(struct dm_struct *dm, int comp, char *fmt, ...) -+{ -+} -+#else -+#define RF_DBG(dm, comp, fmt, args...) -+#endif -+ -+#endif /*#if DBG*/ -+ -+/*@============================================================*/ -+/*@ enumeration */ -+/*@============================================================*/ -+ -+/*@============================================================*/ -+/*@ structure */ -+/*@============================================================*/ -+ -+/*@============================================================*/ -+/*@ function prototype */ -+/*@============================================================*/ -+ -+void halrf_cmd_parser(void *dm_void, char input[][16], u32 *_used, char *output, -+ u32 *_out_len, u32 input_num); -+ -+void halrf_init_debug_setting(void *dm_void); -+ -+#endif /*__HALRF_H__*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_dpk.h linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_dpk.h -new file mode 100644 -index 000000000..c9efc7e93 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_dpk.h -@@ -0,0 +1,86 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * The full GNU General Public License is included in this distribution in the -+ * file called LICENSE. -+ * -+ * Contact Information: -+ * wlanfae -+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, -+ * Hsinchu 300, Taiwan. -+ * -+ * Larry Finger -+ * -+ *****************************************************************************/ -+ -+#ifndef __HALRF_DPK_H__ -+#define __HALRF_DPK_H__ -+ -+/*@--------------------------Define Parameters-------------------------------*/ -+#define GAIN_LOSS 1 -+#define DO_DPK 2 -+#define DPK_ON 3 -+#define DPK_LOK 4 -+#define DPK_TXK 5 -+ -+#define DAGC 4 -+#define LOSS_CHK 0 -+#define GAIN_CHK 1 -+#define PAS_READ 2 -+#define AVG_THERMAL_NUM 8 -+#define AVG_THERMAL_NUM_DPK 8 -+#define THERMAL_DPK_AVG_NUM 4 -+ -+/*@---------------------------End Define Parameters---------------------------*/ -+ -+struct dm_dpk_info { -+ -+ boolean is_dpk_enable; -+ boolean is_dpk_pwr_on; -+ boolean is_dpk_by_channel; -+ u16 dpk_path_ok; -+ /*@BIT(15)~BIT(12) : 5G reserved, BIT(11)~BIT(8) 5G_S3~5G_S0*/ -+ /*@BIT(7)~BIT(4) : 2G reserved, BIT(3)~BIT(0) 2G_S3~2G_S0*/ -+ u8 thermal_dpk; -+ u8 thermal_dpk_avg[AVG_THERMAL_NUM_DPK]; -+ u8 thermal_dpk_avg_index; -+ -+#if (RTL8822C_SUPPORT == 1) -+ u8 result[2][1]; /*path/group*/ -+ u8 tx_agc[2][1]; /*path/group*/ -+ u32 coef[2][1][20]; /*path/group/MDPD coefficient*/ -+#endif -+ -+#if (RTL8198F_SUPPORT == 1 || RTL8192F_SUPPORT == 1 || RTL8197F_SUPPORT == 1) -+ /*2G DPK data*/ -+ u8 dpk_result[4][3]; /*path/group*/ -+ u8 pwsf_2g[4][3]; /*path/group*/ -+ u32 lut_2g_even[4][3][64]; /*path/group/LUT data*/ -+ u32 lut_2g_odd[4][3][64]; /*path/group/LUT data*/ -+#endif -+ -+#if (RTL8195B_SUPPORT == 1) -+ /*2G DPK data*/ -+ u8 dpk_2g_result[1][3]; /*path/group*/ -+ u8 pwsf_2g[1][3]; /*path/group*/ -+ u32 lut_2g_even[1][3][16]; /*path/group/LUT data*/ -+ u32 lut_2g_odd[1][3][16]; /*path/group/LUT data*/ -+ /*5G DPK data*/ -+ u8 dpk_5g_result[1][6]; /*path/group*/ -+ u8 pwsf_5g[1][6]; /*path/group*/ -+ u32 lut_5g_even[1][6][16]; /*path/group/LUT data*/ -+ u32 lut_5g_odd[1][6][16]; /*path/group/LUT data*/ -+#endif -+}; -+ -+#endif /*__HALRF_DPK_H__*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_features.h linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_features.h -new file mode 100644 -index 000000000..da97614be ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_features.h -@@ -0,0 +1,43 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * The full GNU General Public License is included in this distribution in the -+ * file called LICENSE. -+ * -+ * Contact Information: -+ * wlanfae -+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, -+ * Hsinchu 300, Taiwan. -+ * -+ * Larry Finger -+ * -+ *****************************************************************************/ -+ -+#ifndef __HALRF_FEATURES_H__ -+#define __HALRF_FEATURES_H__ -+ -+#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) -+ -+#define CONFIG_HALRF_POWERTRACKING 1 -+ -+#elif (DM_ODM_SUPPORT_TYPE == ODM_AP) -+ -+#define CONFIG_HALRF_POWERTRACKING 1 -+ -+#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) -+ -+#define CONFIG_HALRF_POWERTRACKING 1 -+ -+#endif -+ -+#endif /*#ifndef __HALRF_FEATURES_H__*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_iqk.h linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_iqk.h -new file mode 100644 -index 000000000..0fa676b90 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_iqk.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_iqk.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_iqk.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_iqk.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_iqk.h 2021-03-07 18:16:17.055956100 +0200 @@ -0,0 +1,103 @@ +/****************************************************************************** + * @@ -177654,11 +174681,9 @@ index 000000000..0fa676b90 +}; + +#endif /*__HALRF_IQK_H__*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_kfree.c linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_kfree.c -new file mode 100644 -index 000000000..cee13be26 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_kfree.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_kfree.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_kfree.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_kfree.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_kfree.c 2021-03-07 18:16:17.055956100 +0200 @@ -0,0 +1,1191 @@ +/****************************************************************************** + * @@ -178851,11 +175876,9 @@ index 000000000..cee13be26 + } + RF_DBG(dm, DBG_RF_MP, "<===[kfree] phy_ConfigKFree()\n"); +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_kfree.h linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_kfree.h -new file mode 100644 -index 000000000..d57488ae8 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_kfree.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_kfree.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_kfree.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_kfree.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_kfree.h 2021-03-07 18:16:17.055956100 +0200 @@ -0,0 +1,119 @@ +/****************************************************************************** + * @@ -178976,216 +175999,9 @@ index 000000000..d57488ae8 +void phydm_config_kfree(void *dm_void, u8 channel_to_sw); + +#endif /*__HALRF_KFREE_H__*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking.c linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking.c -new file mode 100644 -index 000000000..eaf53b8ae ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking.c -@@ -0,0 +1,152 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * The full GNU General Public License is included in this distribution in the -+ * file called LICENSE. -+ * -+ * Contact Information: -+ * wlanfae -+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, -+ * Hsinchu 300, Taiwan. -+ * -+ * Larry Finger -+ * -+ *****************************************************************************/ -+ -+/*@************************************************************ -+ * include files -+ * ************************************************************ -+ */ -+#include "mp_precomp.h" -+#include "phydm_precomp.h" -+ -+boolean -+odm_check_power_status(void *dm_void) -+{ -+#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) -+ struct dm_struct *dm = (struct dm_struct *)dm_void; -+ PADAPTER *adapter = dm->adapter; -+ -+ RT_RF_POWER_STATE rt_state; -+ MGNT_INFO *mgnt_info = &((PADAPTER)adapter)->MgntInfo; -+ -+ /* 2011/07/27 MH We are not testing ready~~!! We may fail to get correct value when init sequence. */ -+ if (mgnt_info->init_adpt_in_progress == true) { -+ RF_DBG(dm, DBG_RF_INIT, -+ "check_pow_status Return true, due to initadapter\n"); -+ return true; -+ } -+ -+ /* -+ * 2011/07/19 MH We can not execute tx pwoer tracking/ LLC calibrate or IQK. -+ */ -+ ((PADAPTER)adapter)->HalFunc.GetHwRegHandler((PADAPTER)adapter, HW_VAR_RF_STATE, (u8 *)(&rt_state)); -+ if (((PADAPTER)adapter)->bDriverStopped || ((PADAPTER)adapter)->bDriverIsGoingToPnpSetPowerSleep || rt_state == eRfOff) { -+ RF_DBG(dm, DBG_RF_INIT, -+ "check_pow_status Return false, due to %d/%d/%d\n", -+ ((PADAPTER)adapter)->bDriverStopped, -+ ((PADAPTER)adapter)->bDriverIsGoingToPnpSetPowerSleep, -+ rt_state); -+ return false; -+ } -+#endif -+ return true; -+} -+ -+#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE)) -+void halrf_update_pwr_track(void *dm_void, u8 rate) -+{ -+ struct dm_struct *dm = (struct dm_struct *)dm_void; -+#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) -+ u8 path_idx = 0; -+#endif -+ -+ RF_DBG(dm, DBG_RF_TX_PWR_TRACK, "Pwr Track Get rate=0x%x\n", rate); -+ -+ dm->tx_rate = rate; -+ -+#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) -+#if DEV_BUS_TYPE == RT_PCI_INTERFACE -+#if USE_WORKITEM -+ odm_schedule_work_item(&dm->ra_rpt_workitem); -+#else -+ if (dm->support_ic_type == ODM_RTL8821) { -+#if (RTL8821A_SUPPORT == 1) -+ odm_tx_pwr_track_set_pwr8821a(dm, MIX_MODE, RF_PATH_A, 0); -+#endif -+ } else if (dm->support_ic_type == ODM_RTL8812) { -+ for (path_idx = RF_PATH_A; path_idx < MAX_PATH_NUM_8812A; path_idx++) { -+#if (RTL8812A_SUPPORT == 1) -+ odm_tx_pwr_track_set_pwr8812a(dm, MIX_MODE, path_idx, 0); -+#endif -+ } -+ } else if (dm->support_ic_type == ODM_RTL8723B) { -+#if (RTL8723B_SUPPORT == 1) -+ odm_tx_pwr_track_set_pwr_8723b(dm, MIX_MODE, RF_PATH_A, 0); -+#endif -+ } else if (dm->support_ic_type == ODM_RTL8192E) { -+ for (path_idx = RF_PATH_A; path_idx < MAX_PATH_NUM_8192E; path_idx++) { -+#if (RTL8192E_SUPPORT == 1) -+ odm_tx_pwr_track_set_pwr92_e(dm, MIX_MODE, path_idx, 0); -+#endif -+ } -+ } else if (dm->support_ic_type == ODM_RTL8188E) { -+#if (RTL8188E_SUPPORT == 1) -+ odm_tx_pwr_track_set_pwr88_e(dm, MIX_MODE, RF_PATH_A, 0); -+#endif -+ } -+#endif -+#else -+ odm_schedule_work_item(&dm->ra_rpt_workitem); -+#endif -+#endif -+} -+ -+#endif -+ -+#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) -+void halrf_update_init_rate_work_item_callback( -+ void *context) -+{ -+ void *adapter = (void *)context; -+ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(((PADAPTER)adapter)); -+ struct dm_struct *dm = &hal_data->DM_OutSrc; -+ u8 p = 0; -+ -+ if (dm->support_ic_type == ODM_RTL8821) { -+#if (RTL8821A_SUPPORT == 1) -+ odm_tx_pwr_track_set_pwr8821a(dm, MIX_MODE, RF_PATH_A, 0); -+#endif -+ } else if (dm->support_ic_type == ODM_RTL8812) { -+#if (RTL8812A_SUPPORT == 1) -+ /*Don't know how to include &c*/ -+ for (p = RF_PATH_A; p < MAX_PATH_NUM_8812A; p++) -+ odm_tx_pwr_track_set_pwr8812a(dm, MIX_MODE, p, 0); -+#endif -+ } else if (dm->support_ic_type == ODM_RTL8723B) { -+#if (RTL8723B_SUPPORT == 1) -+ odm_tx_pwr_track_set_pwr_8723b(dm, MIX_MODE, RF_PATH_A, 0); -+#endif -+ } else if (dm->support_ic_type == ODM_RTL8192E) { -+#if (RTL8192E_SUPPORT == 1) -+ /*Don't know how to include &c*/ -+ for (p = RF_PATH_A; p < MAX_PATH_NUM_8192E; p++) -+ odm_tx_pwr_track_set_pwr92_e(dm, MIX_MODE, p, 0); -+#endif -+ } else if (dm->support_ic_type == ODM_RTL8188E) { -+#if (RTL8188E_SUPPORT == 1) -+ odm_tx_pwr_track_set_pwr88_e(dm, MIX_MODE, RF_PATH_A, 0); -+#endif -+ } -+} -+#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking.h linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking.h -new file mode 100644 -index 000000000..c45628854 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking.h -@@ -0,0 +1,41 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * The full GNU General Public License is included in this distribution in the -+ * file called LICENSE. -+ * -+ * Contact Information: -+ * wlanfae -+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, -+ * Hsinchu 300, Taiwan. -+ * -+ * Larry Finger -+ * -+ *****************************************************************************/ -+ -+#ifndef __HALRF_POWER_TRACKING_H__ -+#define __HALRF_POWER_TRACKING_H__ -+ -+boolean -+odm_check_power_status(void *dm_void); -+ -+#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE)) -+void halrf_update_pwr_track(void *dm_void, u8 rate); -+#endif -+ -+#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) -+void halrf_update_init_rate_work_item_callback( -+ void *context); -+#endif -+ -+#endif /*#ifndef __HALRF_POWERTRACKING_H__*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_ap.c linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_ap.c -new file mode 100644 -index 000000000..cafd92f8d ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_ap.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_ap.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_ap.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_ap.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_ap.c 2021-03-07 18:16:17.055956100 +0200 @@ -0,0 +1,1220 @@ +/****************************************************************************** + * @@ -180407,11 +177223,9 @@ index 000000000..cafd92f8d +#endif + +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_ap.h linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_ap.h -new file mode 100644 -index 000000000..1f960cf46 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_ap.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_ap.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_ap.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_ap.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_ap.h 2021-03-07 18:16:17.055956100 +0200 @@ -0,0 +1,398 @@ +/****************************************************************************** + * @@ -180811,11 +177625,165 @@ index 000000000..1f960cf46 + + +#endif /*#ifndef __HALRF_POWER_TRACKING_H__*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_ce.c linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_ce.c -new file mode 100644 -index 000000000..55ec7bf16 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_ce.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking.c 2021-03-07 18:16:17.055956100 +0200 +@@ -0,0 +1,152 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, ++ * Hsinchu 300, Taiwan. ++ * ++ * Larry Finger ++ * ++ *****************************************************************************/ ++ ++/*@************************************************************ ++ * include files ++ * ************************************************************ ++ */ ++#include "mp_precomp.h" ++#include "phydm_precomp.h" ++ ++boolean ++odm_check_power_status(void *dm_void) ++{ ++#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) ++ struct dm_struct *dm = (struct dm_struct *)dm_void; ++ PADAPTER *adapter = dm->adapter; ++ ++ RT_RF_POWER_STATE rt_state; ++ MGNT_INFO *mgnt_info = &((PADAPTER)adapter)->MgntInfo; ++ ++ /* 2011/07/27 MH We are not testing ready~~!! We may fail to get correct value when init sequence. */ ++ if (mgnt_info->init_adpt_in_progress == true) { ++ RF_DBG(dm, DBG_RF_INIT, ++ "check_pow_status Return true, due to initadapter\n"); ++ return true; ++ } ++ ++ /* ++ * 2011/07/19 MH We can not execute tx pwoer tracking/ LLC calibrate or IQK. ++ */ ++ ((PADAPTER)adapter)->HalFunc.GetHwRegHandler((PADAPTER)adapter, HW_VAR_RF_STATE, (u8 *)(&rt_state)); ++ if (((PADAPTER)adapter)->bDriverStopped || ((PADAPTER)adapter)->bDriverIsGoingToPnpSetPowerSleep || rt_state == eRfOff) { ++ RF_DBG(dm, DBG_RF_INIT, ++ "check_pow_status Return false, due to %d/%d/%d\n", ++ ((PADAPTER)adapter)->bDriverStopped, ++ ((PADAPTER)adapter)->bDriverIsGoingToPnpSetPowerSleep, ++ rt_state); ++ return false; ++ } ++#endif ++ return true; ++} ++ ++#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE)) ++void halrf_update_pwr_track(void *dm_void, u8 rate) ++{ ++ struct dm_struct *dm = (struct dm_struct *)dm_void; ++#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) ++ u8 path_idx = 0; ++#endif ++ ++ RF_DBG(dm, DBG_RF_TX_PWR_TRACK, "Pwr Track Get rate=0x%x\n", rate); ++ ++ dm->tx_rate = rate; ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) ++#if DEV_BUS_TYPE == RT_PCI_INTERFACE ++#if USE_WORKITEM ++ odm_schedule_work_item(&dm->ra_rpt_workitem); ++#else ++ if (dm->support_ic_type == ODM_RTL8821) { ++#if (RTL8821A_SUPPORT == 1) ++ odm_tx_pwr_track_set_pwr8821a(dm, MIX_MODE, RF_PATH_A, 0); ++#endif ++ } else if (dm->support_ic_type == ODM_RTL8812) { ++ for (path_idx = RF_PATH_A; path_idx < MAX_PATH_NUM_8812A; path_idx++) { ++#if (RTL8812A_SUPPORT == 1) ++ odm_tx_pwr_track_set_pwr8812a(dm, MIX_MODE, path_idx, 0); ++#endif ++ } ++ } else if (dm->support_ic_type == ODM_RTL8723B) { ++#if (RTL8723B_SUPPORT == 1) ++ odm_tx_pwr_track_set_pwr_8723b(dm, MIX_MODE, RF_PATH_A, 0); ++#endif ++ } else if (dm->support_ic_type == ODM_RTL8192E) { ++ for (path_idx = RF_PATH_A; path_idx < MAX_PATH_NUM_8192E; path_idx++) { ++#if (RTL8192E_SUPPORT == 1) ++ odm_tx_pwr_track_set_pwr92_e(dm, MIX_MODE, path_idx, 0); ++#endif ++ } ++ } else if (dm->support_ic_type == ODM_RTL8188E) { ++#if (RTL8188E_SUPPORT == 1) ++ odm_tx_pwr_track_set_pwr88_e(dm, MIX_MODE, RF_PATH_A, 0); ++#endif ++ } ++#endif ++#else ++ odm_schedule_work_item(&dm->ra_rpt_workitem); ++#endif ++#endif ++} ++ ++#endif ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) ++void halrf_update_init_rate_work_item_callback( ++ void *context) ++{ ++ void *adapter = (void *)context; ++ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(((PADAPTER)adapter)); ++ struct dm_struct *dm = &hal_data->DM_OutSrc; ++ u8 p = 0; ++ ++ if (dm->support_ic_type == ODM_RTL8821) { ++#if (RTL8821A_SUPPORT == 1) ++ odm_tx_pwr_track_set_pwr8821a(dm, MIX_MODE, RF_PATH_A, 0); ++#endif ++ } else if (dm->support_ic_type == ODM_RTL8812) { ++#if (RTL8812A_SUPPORT == 1) ++ /*Don't know how to include &c*/ ++ for (p = RF_PATH_A; p < MAX_PATH_NUM_8812A; p++) ++ odm_tx_pwr_track_set_pwr8812a(dm, MIX_MODE, p, 0); ++#endif ++ } else if (dm->support_ic_type == ODM_RTL8723B) { ++#if (RTL8723B_SUPPORT == 1) ++ odm_tx_pwr_track_set_pwr_8723b(dm, MIX_MODE, RF_PATH_A, 0); ++#endif ++ } else if (dm->support_ic_type == ODM_RTL8192E) { ++#if (RTL8192E_SUPPORT == 1) ++ /*Don't know how to include &c*/ ++ for (p = RF_PATH_A; p < MAX_PATH_NUM_8192E; p++) ++ odm_tx_pwr_track_set_pwr92_e(dm, MIX_MODE, p, 0); ++#endif ++ } else if (dm->support_ic_type == ODM_RTL8188E) { ++#if (RTL8188E_SUPPORT == 1) ++ odm_tx_pwr_track_set_pwr88_e(dm, MIX_MODE, RF_PATH_A, 0); ++#endif ++ } ++} ++#endif +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_ce.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_ce.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_ce.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_ce.c 2021-03-07 18:16:17.055956100 +0200 @@ -0,0 +1,869 @@ +/****************************************************************************** + * @@ -181686,11 +178654,9 @@ index 000000000..55ec7bf16 + +#endif +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_ce.h linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_ce.h -new file mode 100644 -index 000000000..4b96ccc7e ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_ce.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_ce.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_ce.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_ce.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_ce.h 2021-03-07 18:16:17.056956148 +0200 @@ -0,0 +1,327 @@ +/****************************************************************************** + * @@ -182019,11 +178985,54 @@ index 000000000..4b96ccc7e +#endif + +#endif /*__HALRF_POWER_TRACKING_H__*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_iot.c linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_iot.c -new file mode 100644 -index 000000000..a0c40dc9d ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_iot.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking.h 2021-03-07 18:16:17.055956100 +0200 +@@ -0,0 +1,41 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, ++ * Hsinchu 300, Taiwan. ++ * ++ * Larry Finger ++ * ++ *****************************************************************************/ ++ ++#ifndef __HALRF_POWER_TRACKING_H__ ++#define __HALRF_POWER_TRACKING_H__ ++ ++boolean ++odm_check_power_status(void *dm_void); ++ ++#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE)) ++void halrf_update_pwr_track(void *dm_void, u8 rate); ++#endif ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) ++void halrf_update_init_rate_work_item_callback( ++ void *context); ++#endif ++ ++#endif /*#ifndef __HALRF_POWERTRACKING_H__*/ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_iot.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_iot.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_iot.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_iot.c 2021-03-07 18:16:17.056956148 +0200 @@ -0,0 +1,741 @@ +/****************************************************************************** + * @@ -182766,11 +179775,9 @@ index 000000000..a0c40dc9d + +#endif +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_iot.h linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_iot.h -new file mode 100644 -index 000000000..55460a62e ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_iot.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_iot.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_iot.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_iot.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_iot.h 2021-03-07 18:16:17.056956148 +0200 @@ -0,0 +1,349 @@ +/****************************************************************************** + * @@ -183121,11 +180128,9 @@ index 000000000..55460a62e +#endif + +#endif /*#ifndef __HALRF_POWER_TRACKING_H__*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_win.c linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_win.c -new file mode 100644 -index 000000000..bad28f508 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_win.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_win.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_win.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_win.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_win.c 2021-03-07 18:16:17.056956148 +0200 @@ -0,0 +1,861 @@ +/****************************************************************************** + * @@ -183988,11 +180993,9 @@ index 000000000..bad28f508 +} + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_win.h linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_win.h -new file mode 100644 -index 000000000..3ecdc1d0f ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_win.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_win.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_win.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_win.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_win.h 2021-03-07 18:16:17.056956148 +0200 @@ -0,0 +1,302 @@ +/****************************************************************************** + * @@ -184296,11 +181299,9 @@ index 000000000..3ecdc1d0f + + +#endif /*#ifndef __HALRF_POWER_TRACKING_H__*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_psd.c linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_psd.c -new file mode 100644 -index 000000000..8c2f87429 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_psd.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_psd.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_psd.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_psd.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_psd.c 2021-03-07 18:16:17.056956148 +0200 @@ -0,0 +1,428 @@ +/****************************************************************************** + * @@ -184730,11 +181731,9 @@ index 000000000..8c2f87429 +} + +#endif /*#if (DM_ODM_SUPPORT_TYPE & ODM_WIN)*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_psd.h linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_psd.h -new file mode 100644 -index 000000000..986ff8815 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_psd.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_psd.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_psd.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_psd.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_psd.h 2021-03-07 18:16:17.056956148 +0200 @@ -0,0 +1,52 @@ +/****************************************************************************** + * @@ -184788,11 +181787,9 @@ index 000000000..986ff8815 + +#endif /*#if (DM_ODM_SUPPORT_TYPE & ODM_WIN)*/ +#endif /*#__HALRF_PSD_H__*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_txgapcal.c linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_txgapcal.c -new file mode 100644 -index 000000000..0cc44974b ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_txgapcal.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_txgapcal.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_txgapcal.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_txgapcal.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_txgapcal.c 2021-03-07 18:16:17.056956148 +0200 @@ -0,0 +1,300 @@ +/****************************************************************************** + * @@ -185094,11 +182091,9 @@ index 000000000..0cc44974b + odm_tx_gain_gap_calibration_8197f(dm_void); +#endif +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_txgapcal.h linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_txgapcal.h -new file mode 100644 -index 000000000..09651cbee ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/halrf_txgapcal.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_txgapcal.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_txgapcal.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_txgapcal.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/halrf_txgapcal.h 2021-03-07 18:16:17.056956148 +0200 @@ -0,0 +1,31 @@ +/****************************************************************************** + * @@ -185131,11 +182126,9 @@ index 000000000..09651cbee +void odm_tx_gain_gap_calibration(void *dm_void); + +#endif /*__HALRF_TXGAPCAL_H__*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ap.c linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ap.c -new file mode 100644 -index 000000000..8861416bf ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ap.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ap.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ap.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ap.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ap.c 2021-03-07 18:16:17.056956148 +0200 @@ -0,0 +1,2169 @@ +/****************************************************************************** + * @@ -187306,11 +184299,9 @@ index 000000000..8861416bf + _phy_set_rf_path_switch_8812a(dm, is_main, false); + } +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ap.h linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ap.h -new file mode 100644 -index 000000000..52ad7a59d ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ap.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ap.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ap.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ap.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ap.h 2021-03-07 18:16:17.056956148 +0200 @@ -0,0 +1,82 @@ +/****************************************************************************** + * @@ -187394,11 +184385,9 @@ index 000000000..52ad7a59d + + +#endif /*#ifndef __HALRF_8812A_H__*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c -new file mode 100644 -index 000000000..cebb7265d ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c 2021-03-07 18:16:17.057956195 +0200 @@ -0,0 +1,1975 @@ +/****************************************************************************** + * @@ -189375,11 +186364,9 @@ index 000000000..cebb7265d + RF_DBG(dm, DBG_RF_IQK, "<=== %s\n", __func__); +#endif +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.h linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.h -new file mode 100644 -index 000000000..d02537c1e ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.h 2021-03-07 18:16:17.057956195 +0200 @@ -0,0 +1,63 @@ +/****************************************************************************** + * @@ -189444,11 +186431,9 @@ index 000000000..d02537c1e +#endif + boolean is_main); +#endif /*#ifndef __HALRF_8812A_H__*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_win.c linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_win.c -new file mode 100644 -index 000000000..8a08f6b46 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_win.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_win.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_win.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_win.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_win.c 2021-03-07 18:16:17.057956195 +0200 @@ -0,0 +1,2881 @@ +/****************************************************************************** + * @@ -192331,11 +189316,9 @@ index 000000000..8a08f6b46 +#endif +} +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_win.h linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_win.h -new file mode 100644 -index 000000000..28e5c2de9 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_win.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_win.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_win.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_win.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_win.h 2021-03-07 18:16:17.057956195 +0200 @@ -0,0 +1,99 @@ +/****************************************************************************** + * @@ -192436,11 +189419,9 @@ index 000000000..28e5c2de9 + + +#endif /*#ifndef __HALRF_8812A_H__*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ap.c linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ap.c -new file mode 100644 -index 000000000..238df1bf4 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ap.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ap.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ap.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ap.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ap.c 2021-03-07 18:16:17.057956195 +0200 @@ -0,0 +1,1754 @@ +/****************************************************************************** + * @@ -194196,11 +191177,9 @@ index 000000000..238df1bf4 +#endif + + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ap.h linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ap.h -new file mode 100644 -index 000000000..46eaa801e ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ap.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ap.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ap.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ap.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ap.h 2021-03-07 18:16:17.057956195 +0200 @@ -0,0 +1,164 @@ +/****************************************************************************** + * @@ -194366,11 +191345,9 @@ index 000000000..46eaa801e + +#endif // #ifndef __HAL_PHY_RF_8814A_H__ + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.c linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.c -new file mode 100644 -index 000000000..09c65ed3f ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.c 2021-03-07 18:16:17.057956195 +0200 @@ -0,0 +1,564 @@ +/****************************************************************************** + * @@ -194936,11 +191913,9 @@ index 000000000..09c65ed3f + + + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.h linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.h -new file mode 100644 -index 000000000..1f885b32e ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.h 2021-03-07 18:16:17.057956195 +0200 @@ -0,0 +1,112 @@ +/****************************************************************************** + * @@ -195054,11 +192029,9 @@ index 000000000..1f885b32e + +#endif // #ifndef __HAL_PHY_RF_8188E_H__ + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_win.c linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_win.c -new file mode 100644 -index 000000000..eb91c4d8a ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_win.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_win.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_win.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_win.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_win.c 2021-03-07 18:16:17.057956195 +0200 @@ -0,0 +1,528 @@ +/****************************************************************************** + * @@ -195588,11 +192561,9 @@ index 000000000..eb91c4d8a + IN BOOLEAN bReCovery + ){} +#endif /* (RTL8814A_SUPPORT == 0)*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_win.h linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_win.h -new file mode 100644 -index 000000000..658d6f063 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_win.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_win.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_win.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_win.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_win.h 2021-03-07 18:16:17.057956195 +0200 @@ -0,0 +1,106 @@ +/****************************************************************************** + * @@ -195700,11 +192671,9 @@ index 000000000..658d6f063 + +#endif // #ifndef __HAL_PHY_RF_8188E_H__ + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_iqk_8814a.c linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_iqk_8814a.c -new file mode 100644 -index 000000000..e019df35a ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_iqk_8814a.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_iqk_8814a.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_iqk_8814a.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_iqk_8814a.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_iqk_8814a.c 2021-03-07 18:16:17.057956195 +0200 @@ -0,0 +1,557 @@ +/****************************************************************************** + * @@ -196263,11 +193232,9 @@ index 000000000..e019df35a + } +} + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_iqk_8814a.h linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_iqk_8814a.h -new file mode 100644 -index 000000000..15d9cf037 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_iqk_8814a.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_iqk_8814a.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_iqk_8814a.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_iqk_8814a.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_iqk_8814a.h 2021-03-07 18:16:17.058956242 +0200 @@ -0,0 +1,58 @@ +/****************************************************************************** + * @@ -196327,11 +193294,9 @@ index 000000000..15d9cf037 + ); + + #endif /* #ifndef __PHYDM_IQK_8814A_H__*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_ce.c linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_ce.c -new file mode 100644 -index 000000000..ef0f72c56 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_ce.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_ce.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_ce.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_ce.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_ce.c 2021-03-07 18:16:17.058956242 +0200 @@ -0,0 +1,313 @@ +/****************************************************************************** + * @@ -196646,11 +193611,9 @@ index 000000000..ef0f72c56 + + phy_lc_calibrate_8812a(dm); +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_ce.h linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_ce.h -new file mode 100644 -index 000000000..684852a77 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_ce.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_ce.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_ce.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_ce.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_ce.h 2021-03-07 18:16:17.058956242 +0200 @@ -0,0 +1,53 @@ +/****************************************************************************** + * @@ -196705,11 +193668,9 @@ index 000000000..684852a77 +); + +#endif /* #ifndef __HAL_PHY_RF_8821A_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_win.c linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_win.c -new file mode 100644 -index 000000000..cfb7592db ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_win.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_win.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_win.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_win.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_win.c 2021-03-07 18:16:17.058956242 +0200 @@ -0,0 +1,1046 @@ +/****************************************************************************** + * @@ -197757,11 +194718,9 @@ index 000000000..cfb7592db + + phy_lc_calibrate_8812a(dm); +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_win.h linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_win.h -new file mode 100644 -index 000000000..2f50dac05 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_win.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_win.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_win.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_win.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_win.h 2021-03-07 18:16:17.058956242 +0200 @@ -0,0 +1,72 @@ +/****************************************************************************** + * @@ -197835,11 +194794,9 @@ index 000000000..2f50dac05 +); + +#endif /* #ifndef __HAL_PHY_RF_8821A_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ap.c linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ap.c -new file mode 100644 -index 000000000..c98cbc01c ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ap.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ap.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ap.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ap.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ap.c 2021-03-07 18:16:17.058956242 +0200 @@ -0,0 +1,731 @@ +/****************************************************************************** + * @@ -198572,12 +195529,10 @@ index 000000000..c98cbc01c + + _phy_iq_calibrate_8821a(dm); +} -\ No newline at end of file -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ap.h linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ap.h -new file mode 100644 -index 000000000..82cbf62ff ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ap.h +\ Ingen nyrad vid filslut +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ap.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ap.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ap.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ap.h 2021-03-07 18:16:17.058956242 +0200 @@ -0,0 +1,42 @@ +/****************************************************************************** + * @@ -198621,11 +195576,9 @@ index 000000000..82cbf62ff +); +#endif +#endif /* #ifndef __PHYDM_IQK_8821A_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ce.c linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ce.c -new file mode 100644 -index 000000000..b6491baf7 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ce.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ce.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ce.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ce.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ce.c 2021-03-07 18:16:17.058956242 +0200 @@ -0,0 +1,773 @@ +/****************************************************************************** + * @@ -199400,11 +196353,9 @@ index 000000000..b6491baf7 + _phy_iq_calibrate_8821a(dm); +} +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ce.h linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ce.h -new file mode 100644 -index 000000000..23d61e5c7 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ce.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ce.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ce.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ce.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ce.h 2021-03-07 18:16:17.058956242 +0200 @@ -0,0 +1,41 @@ +/****************************************************************************** + * @@ -199447,11 +196398,9 @@ index 000000000..23d61e5c7 +); +#endif +#endif /* #ifndef __PHYDM_IQK_8821A_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_win.c linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_win.c -new file mode 100644 -index 000000000..e1c267a5f ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_win.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_win.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_win.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_win.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_win.c 2021-03-07 18:16:17.058956242 +0200 @@ -0,0 +1,774 @@ +/****************************************************************************** + * @@ -200227,11 +197176,9 @@ index 000000000..e1c267a5f + _phy_iq_calibrate_8821a(dm); +} +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_win.h linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_win.h -new file mode 100644 -index 000000000..d325102b8 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_win.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_win.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_win.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_win.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_win.h 2021-03-07 18:16:17.058956242 +0200 @@ -0,0 +1,42 @@ +/****************************************************************************** + * @@ -200275,11 +197222,9 @@ index 000000000..d325102b8 +); +#endif +#endif /* #ifndef __PHYDM_IQK_8821A_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/mp_precomp.h linux-5.8/3rdparty/rtl8812au/hal/phydm/mp_precomp.h -new file mode 100644 -index 000000000..897adc13f ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/mp_precomp.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/mp_precomp.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/mp_precomp.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/mp_precomp.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/mp_precomp.h 2021-03-07 18:16:17.058956242 +0200 @@ -0,0 +1,24 @@ +/****************************************************************************** + * @@ -200305,4877 +197250,9 @@ index 000000000..897adc13f + * Larry Finger + * + *****************************************************************************/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm.c linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm.c -new file mode 100644 -index 000000000..1e980630e ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm.c -@@ -0,0 +1,3265 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * The full GNU General Public License is included in this distribution in the -+ * file called LICENSE. -+ * -+ * Contact Information: -+ * wlanfae -+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, -+ * Hsinchu 300, Taiwan. -+ * -+ * Larry Finger -+ * -+ *****************************************************************************/ -+ -+/*@************************************************************ -+ * include files -+ ************************************************************/ -+ -+#include "mp_precomp.h" -+#include "phydm_precomp.h" -+ -+const u16 phy_rate_table[] = { -+ /*@20M*/ -+ 1, 2, 5, 11, -+ 6, 9, 12, 18, 24, 36, 48, 54, -+ 6, 13, 19, 26, 39, 52, 58, 65, /*@MCS0~7*/ -+ 13, 26, 39, 52, 78, 104, 117, 130 /*@MCS8~15*/ -+}; -+ -+void phydm_traffic_load_decision(void *dm_void) -+{ -+ struct dm_struct *dm = (struct dm_struct *)dm_void; -+ u8 shift = 0; -+ -+ /*@---TP & Trafic-load calculation---*/ -+ -+ if (dm->last_tx_ok_cnt > *dm->num_tx_bytes_unicast) -+ dm->last_tx_ok_cnt = *dm->num_tx_bytes_unicast; -+ -+ if (dm->last_rx_ok_cnt > *dm->num_rx_bytes_unicast) -+ dm->last_rx_ok_cnt = *dm->num_rx_bytes_unicast; -+ -+ dm->cur_tx_ok_cnt = *dm->num_tx_bytes_unicast - dm->last_tx_ok_cnt; -+ dm->cur_rx_ok_cnt = *dm->num_rx_bytes_unicast - dm->last_rx_ok_cnt; -+ dm->last_tx_ok_cnt = *dm->num_tx_bytes_unicast; -+ dm->last_rx_ok_cnt = *dm->num_rx_bytes_unicast; -+ -+ /*@AP: <<3(8bit), >>20(10^6,M), >>0(1sec)*/ -+ shift = 17 + (PHYDM_WATCH_DOG_PERIOD - 1); -+ /*@WIN&CE: <<3(8bit), >>20(10^6,M), >>1(2sec)*/ -+ -+ dm->tx_tp = (dm->tx_tp >> 1) + (u32)((dm->cur_tx_ok_cnt >> shift) >> 1); -+ dm->rx_tp = (dm->rx_tp >> 1) + (u32)((dm->cur_rx_ok_cnt >> shift) >> 1); -+ -+ dm->total_tp = dm->tx_tp + dm->rx_tp; -+ -+ /*@[Calculate TX/RX state]*/ -+ if (dm->tx_tp > (dm->rx_tp << 1)) -+ dm->txrx_state_all = TX_STATE; -+ else if (dm->rx_tp > (dm->tx_tp << 1)) -+ dm->txrx_state_all = RX_STATE; -+ else -+ dm->txrx_state_all = BI_DIRECTION_STATE; -+ -+ /*@[Traffic load decision]*/ -+ dm->pre_traffic_load = dm->traffic_load; -+ -+ if (dm->cur_tx_ok_cnt > 1875000 || dm->cur_rx_ok_cnt > 1875000) { -+ /* @( 1.875M * 8bit ) / 2sec= 7.5M bits /sec )*/ -+ dm->traffic_load = TRAFFIC_HIGH; -+ } else if (dm->cur_tx_ok_cnt > 500000 || dm->cur_rx_ok_cnt > 500000) { -+ /*@( 0.5M * 8bit ) / 2sec = 2M bits /sec )*/ -+ dm->traffic_load = TRAFFIC_MID; -+ } else if (dm->cur_tx_ok_cnt > 100000 || dm->cur_rx_ok_cnt > 100000) { -+ /*@( 0.1M * 8bit ) / 2sec = 0.4M bits /sec )*/ -+ dm->traffic_load = TRAFFIC_LOW; -+ } else if (dm->cur_tx_ok_cnt > 25000 || dm->cur_rx_ok_cnt > 25000) { -+ /*@( 0.025M * 8bit ) / 2sec = 0.1M bits /sec )*/ -+ dm->traffic_load = TRAFFIC_ULTRA_LOW; -+ } else { -+ dm->traffic_load = TRAFFIC_NO_TP; -+ } -+ -+ /*@[Calculate consecutive idlel time]*/ -+ if (dm->traffic_load == 0) -+ dm->consecutive_idlel_time += PHYDM_WATCH_DOG_PERIOD; -+ else -+ dm->consecutive_idlel_time = 0; -+ -+ #if 0 -+ PHYDM_DBG(dm, DBG_COMMON_FLOW, -+ "cur_tx_ok_cnt = %d, cur_rx_ok_cnt = %d, last_tx_ok_cnt = %d, last_rx_ok_cnt = %d\n", -+ dm->cur_tx_ok_cnt, dm->cur_rx_ok_cnt, dm->last_tx_ok_cnt, -+ dm->last_rx_ok_cnt); -+ -+ PHYDM_DBG(dm, DBG_COMMON_FLOW, "tx_tp = %d, rx_tp = %d\n", dm->tx_tp, -+ dm->rx_tp); -+ #endif -+} -+ -+void phydm_cck_new_agc_chk(struct dm_struct *dm) -+{ -+ dm->cck_new_agc = 0; -+ -+#if ((RTL8723D_SUPPORT == 1) || (RTL8822B_SUPPORT == 1) || \ -+ (RTL8821C_SUPPORT == 1) || (RTL8197F_SUPPORT == 1) || \ -+ (RTL8710B_SUPPORT == 1) || (RTL8192F_SUPPORT == 1) || \ -+ (RTL8195B_SUPPORT == 1) || (RTL8198F_SUPPORT == 1) || \ -+ (RTL8822C_SUPPORT == 1) || (RTL8721D_SUPPORT == 1)) -+ if (dm->support_ic_type & -+ (ODM_RTL8723D | ODM_RTL8822B | ODM_RTL8821C | ODM_RTL8197F | -+ ODM_RTL8710B | ODM_RTL8192F | ODM_RTL8195B | ODM_RTL8721D)) { -+ /*@1: new agc 0: old agc*/ -+ dm->cck_new_agc = (boolean)odm_get_bb_reg(dm, R_0xa9c, BIT(17)); -+ } else if (dm->support_ic_type & (ODM_RTL8198F | ODM_RTL8822C)) { -+ /*@1: new agc 0: old agc*/ -+ dm->cck_new_agc = (boolean)odm_get_bb_reg(dm, R_0x1a9c, -+ BIT(17)); -+ } -+#endif -+} -+ -+/*select 3 or 4 bit LNA */ -+void phydm_cck_lna_bit_num_chk(struct dm_struct *dm) -+{ -+ boolean report_type = 0; -+ #if (RTL8192E_SUPPORT == 1) -+ u32 value_824, value_82c; -+ #endif -+ -+ #if (RTL8192E_SUPPORT == 1) -+ if (dm->support_ic_type & (ODM_RTL8192E)) { -+ /* @0x824[9] = 0x82C[9] = 0xA80[7] those registers setting -+ * should be equal or CCK RSSI report may be incorrect -+ */ -+ value_824 = odm_get_bb_reg(dm, R_0x824, BIT(9)); -+ value_82c = odm_get_bb_reg(dm, R_0x82c, BIT(9)); -+ -+ if (value_824 != value_82c) -+ odm_set_bb_reg(dm, R_0x82c, BIT(9), value_824); -+ odm_set_bb_reg(dm, R_0xa80, BIT(7), value_824); -+ report_type = (boolean)value_824; -+ } -+ #endif -+ -+ #if (RTL8703B_SUPPORT || RTL8723D_SUPPORT || RTL8710B_SUPPORT) -+ if (dm->support_ic_type & -+ (ODM_RTL8703B | ODM_RTL8723D | ODM_RTL8710B)) { -+ report_type = (boolean)odm_get_bb_reg(dm, R_0x950, BIT(11)); -+ -+ if (report_type != 1) -+ pr_debug("[Warning] CCK should be 4bit LNA\n"); -+ } -+ #endif -+ -+ #if (RTL8821C_SUPPORT == 1) -+ if (dm->support_ic_type & ODM_RTL8821C) { -+ if (dm->default_rf_set_8821c == SWITCH_TO_BTG) -+ report_type = 1; -+ } -+ #endif -+ -+ dm->cck_agc_report_type = report_type; -+ -+ PHYDM_DBG(dm, ODM_COMP_INIT, "cck_agc_report_type=((%d))\n", -+ dm->cck_agc_report_type); -+} -+ -+void phydm_init_cck_setting(struct dm_struct *dm) -+{ -+ u32 reg_tmp = 0; -+ u32 mask_tmp = 0; -+ -+ reg_tmp = ODM_REG(CCK_RPT_FORMAT, dm); -+ mask_tmp = ODM_BIT(CCK_RPT_FORMAT, dm); -+ dm->is_cck_high_power = (boolean)odm_get_bb_reg(dm, reg_tmp, mask_tmp); -+ -+ PHYDM_DBG(dm, ODM_COMP_INIT, "ext_lna_gain=((%d))\n", dm->ext_lna_gain); -+ -+ phydm_config_cck_rx_antenna_init(dm); -+ -+ if (dm->support_ic_type & (ODM_RTL8192F)) -+ phydm_config_cck_rx_path(dm, BB_PATH_AB); -+ else -+ phydm_config_cck_rx_path(dm, BB_PATH_A); -+ -+ phydm_cck_new_agc_chk(dm); -+ phydm_cck_lna_bit_num_chk(dm); -+ phydm_get_cck_rssi_table_from_reg(dm); -+} -+ -+void phydm_init_hw_info_by_rfe(struct dm_struct *dm) -+{ -+#if (RTL8822B_SUPPORT == 1) -+ /*@if (dm->support_ic_type & ODM_RTL8822B)*/ -+ /*@phydm_init_hw_info_by_rfe_type_8822b(dm);*/ -+#endif -+#if (RTL8821C_SUPPORT == 1) -+ if (dm->support_ic_type & ODM_RTL8821C) -+ phydm_init_hw_info_by_rfe_type_8821c(dm); -+#endif -+#if (RTL8197F_SUPPORT == 1) -+ if (dm->support_ic_type & ODM_RTL8197F) -+ phydm_init_hw_info_by_rfe_type_8197f(dm); -+#endif -+} -+ -+void phydm_common_info_self_init(struct dm_struct *dm) -+{ -+ u32 reg_tmp = 0; -+ u32 mask_tmp = 0; -+ -+ /*@BB IP Generation*/ -+ if (dm->support_ic_type & ODM_IC_JGR3_SERIES) -+ dm->ic_ip_series = PHYDM_IC_JGR3; -+ else if (dm->support_ic_type & ODM_IC_11AC_SERIES) -+ dm->ic_ip_series = PHYDM_IC_AC; -+ else if (dm->support_ic_type & ODM_IC_11N_SERIES) -+ dm->ic_ip_series = PHYDM_IC_N; -+ -+ /*@BB phy-status Generation*/ -+ if (dm->support_ic_type & PHYSTS_3RD_TYPE_IC) -+ dm->ic_phy_sts_type = PHYDM_PHYSTS_TYPE_3; -+ else if (dm->support_ic_type & PHYSTS_2ND_TYPE_IC) -+ dm->ic_phy_sts_type = PHYDM_PHYSTS_TYPE_2; -+ else -+ dm->ic_phy_sts_type = PHYDM_PHYSTS_TYPE_1; -+ -+ phydm_init_cck_setting(dm); -+ -+ reg_tmp = ODM_REG(BB_RX_PATH, dm); -+ mask_tmp = ODM_BIT(BB_RX_PATH, dm); -+ dm->rf_path_rx_enable = (u8)odm_get_bb_reg(dm, reg_tmp, mask_tmp); -+#if (DM_ODM_SUPPORT_TYPE != ODM_CE) -+ dm->is_net_closed = &dm->BOOLEAN_temp; -+ -+ phydm_init_debug_setting(dm); -+#endif -+ phydm_init_soft_ml_setting(dm); -+ -+ dm->phydm_sys_up_time = 0; -+ -+ if (dm->support_ic_type & ODM_IC_1SS) -+ dm->num_rf_path = 1; -+ else if (dm->support_ic_type & ODM_IC_2SS) -+ dm->num_rf_path = 2; -+ #if 0 -+ /* @RTK do not has IC which is equipped with 3 RF paths, -+ * so ODM_IC_3SS is an enpty macro and result in coverity check errors -+ */ -+ else if (dm->support_ic_type & ODM_IC_3SS) -+ dm->num_rf_path = 3; -+ #endif -+ else if (dm->support_ic_type & ODM_IC_4SS) -+ dm->num_rf_path = 4; -+ else -+ dm->num_rf_path = 1; -+ -+ phydm_trx_antenna_setting_init(dm, dm->num_rf_path); -+ -+ dm->tx_rate = 0xFF; -+ dm->rssi_min_by_path = 0xFF; -+ -+ dm->number_linked_client = 0; -+ dm->pre_number_linked_client = 0; -+ dm->number_active_client = 0; -+ dm->pre_number_active_client = 0; -+ -+ dm->last_tx_ok_cnt = 0; -+ dm->last_rx_ok_cnt = 0; -+ dm->tx_tp = 0; -+ dm->rx_tp = 0; -+ dm->total_tp = 0; -+ dm->traffic_load = TRAFFIC_LOW; -+ -+ dm->nbi_set_result = 0; -+ dm->is_init_hw_info_by_rfe = false; -+ dm->pre_dbg_priority = DBGPORT_RELEASE; -+ dm->tp_active_th = 5; -+ dm->disable_phydm_watchdog = 0; -+ -+ dm->u8_dummy = 0xf; -+ dm->u16_dummy = 0xffff; -+ dm->u32_dummy = 0xffffffff; -+ -+ dm->pause_lv_table.lv_cckpd = PHYDM_PAUSE_RELEASE; -+ dm->pause_lv_table.lv_dig = PHYDM_PAUSE_RELEASE; -+} -+ -+void phydm_cmn_sta_info_update(void *dm_void, u8 macid) -+{ -+ struct dm_struct *dm = (struct dm_struct *)dm_void; -+ struct cmn_sta_info *sta = dm->phydm_sta_info[macid]; -+ struct ra_sta_info *ra = NULL; -+ -+ if (is_sta_active(sta)) { -+ ra = &sta->ra_info; -+ } else { -+ PHYDM_DBG(dm, DBG_RA_MASK, "[Warning] %s invalid sta_info\n", -+ __func__); -+ return; -+ } -+ -+ PHYDM_DBG(dm, DBG_RA_MASK, "%s ======>\n", __func__); -+ PHYDM_DBG(dm, DBG_RA_MASK, "MACID=%d\n", sta->mac_id); -+ -+ /*@[Calculate TX/RX state]*/ -+ if (sta->tx_moving_average_tp > (sta->rx_moving_average_tp << 1)) -+ ra->txrx_state = TX_STATE; -+ else if (sta->rx_moving_average_tp > (sta->tx_moving_average_tp << 1)) -+ ra->txrx_state = RX_STATE; -+ else -+ ra->txrx_state = BI_DIRECTION_STATE; -+ -+ ra->is_noisy = dm->noisy_decision; -+} -+ -+void phydm_common_info_self_update(struct dm_struct *dm) -+{ -+ u8 sta_cnt = 0, num_active_client = 0; -+ u32 i, one_entry_macid = 0; -+ u32 ma_rx_tp = 0; -+ u32 tp_diff = 0; -+ struct cmn_sta_info *sta; -+ -+#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) -+ -+ PADAPTER adapter = (PADAPTER)dm->adapter; -+ -+ PMGNT_INFO mgnt_info = &((PADAPTER)adapter)->MgntInfo; -+ -+ sta = dm->phydm_sta_info[0]; -+ if (mgnt_info->mAssoc) { -+ sta->dm_ctrl |= STA_DM_CTRL_ACTIVE; -+ for (i = 0; i < 6; i++) -+ sta->mac_addr[i] = mgnt_info->Bssid[i]; -+ } else if (GetFirstClientPort(adapter)) { -+ //void *client_adapter = GetFirstClientPort(adapter); -+ struct _ADAPTER *client_adapter = GetFirstClientPort(adapter); -+ -+ sta->dm_ctrl |= STA_DM_CTRL_ACTIVE; -+ for (i = 0; i < 6; i++) -+ sta->mac_addr[i] = client_adapter->MgntInfo.Bssid[i]; -+ } else { -+ sta->dm_ctrl = sta->dm_ctrl & (~STA_DM_CTRL_ACTIVE); -+ for (i = 0; i < 6; i++) -+ sta->mac_addr[i] = 0; -+ } -+ -+ /* STA mode is linked to AP */ -+ if (is_sta_active(sta) && !ACTING_AS_AP(adapter)) -+ dm->bsta_state = true; -+ else -+ dm->bsta_state = false; -+#endif -+ -+ for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) { -+ sta = dm->phydm_sta_info[i]; -+ if (is_sta_active(sta)) { -+ sta_cnt++; -+ -+ if (sta_cnt == 1) -+ one_entry_macid = i; -+ -+ phydm_cmn_sta_info_update(dm, (u8)i); -+ #ifdef PHYDM_BEAMFORMING_SUPPORT -+ /*@phydm_get_txbf_device_num(dm, (u8)i);*/ -+ #endif -+ -+ ma_rx_tp = sta->rx_moving_average_tp + -+ sta->tx_moving_average_tp; -+ -+ PHYDM_DBG(dm, DBG_COMMON_FLOW, -+ "TP[%d]: ((%d )) bit/sec\n", i, ma_rx_tp); -+ -+ if (ma_rx_tp > ACTIVE_TP_THRESHOLD) -+ num_active_client++; -+ } -+ } -+ -+#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) -+ dm->is_linked = (sta_cnt != 0) ? true : false; -+#endif -+ -+ if (sta_cnt == 1) { -+ dm->is_one_entry_only = true; -+ dm->one_entry_macid = one_entry_macid; -+ dm->one_entry_tp = ma_rx_tp; -+ -+ dm->tp_active_occur = 0; -+ -+ PHYDM_DBG(dm, DBG_COMMON_FLOW, -+ "one_entry_tp=((%d)), pre_one_entry_tp=((%d))\n", -+ dm->one_entry_tp, dm->pre_one_entry_tp); -+ -+ if (dm->one_entry_tp > dm->pre_one_entry_tp && -+ dm->pre_one_entry_tp <= 2) { -+ tp_diff = dm->one_entry_tp - dm->pre_one_entry_tp; -+ -+ if (tp_diff > dm->tp_active_th) -+ dm->tp_active_occur = 1; -+ } -+ dm->pre_one_entry_tp = dm->one_entry_tp; -+ } else { -+ dm->is_one_entry_only = false; -+ } -+ -+ dm->pre_number_linked_client = dm->number_linked_client; -+ dm->pre_number_active_client = dm->number_active_client; -+ -+ dm->number_linked_client = sta_cnt; -+ dm->number_active_client = num_active_client; -+ -+ /*Traffic load information update*/ -+ phydm_traffic_load_decision(dm); -+ -+ dm->phydm_sys_up_time += PHYDM_WATCH_DOG_PERIOD; -+ -+ dm->is_dfs_band = phydm_is_dfs_band(dm); -+ dm->phy_dbg_info.show_phy_sts_cnt = 0; -+} -+ -+void phydm_common_info_self_reset(struct dm_struct *dm) -+{ -+ struct odm_phy_dbg_info *dbg_t = &dm->phy_dbg_info; -+ -+ dbg_t->beacon_cnt_in_period = dbg_t->num_qry_beacon_pkt; -+ dbg_t->num_qry_beacon_pkt = 0; -+ -+ dm->rxsc_l = 0xff; -+ dm->rxsc_20 = 0xff; -+ dm->rxsc_40 = 0xff; -+ dm->rxsc_80 = 0xff; -+} -+ -+void * -+phydm_get_structure(struct dm_struct *dm, u8 structure_type) -+ -+{ -+ void *structure = NULL; -+ -+ switch (structure_type) { -+ case PHYDM_FALSEALMCNT: -+ structure = &dm->false_alm_cnt; -+ break; -+ -+ case PHYDM_CFOTRACK: -+ structure = &dm->dm_cfo_track; -+ break; -+ -+ case PHYDM_ADAPTIVITY: -+ structure = &dm->adaptivity; -+ break; -+ -+ case PHYDM_DFS: -+ structure = &dm->dfs; -+ break; -+ -+ default: -+ break; -+ } -+ -+ return structure; -+} -+ -+void phydm_phy_info_update(struct dm_struct *dm) -+{ -+#if (RTL8822B_SUPPORT == 1) -+ if (dm->support_ic_type == ODM_RTL8822B) -+ dm->phy_dbg_info.condi_num = phydm_get_condi_num_8822b(dm); -+#endif -+} -+ -+void phydm_hw_setting(struct dm_struct *dm) -+{ -+#if (RTL8821A_SUPPORT == 1) -+ if (dm->support_ic_type & ODM_RTL8821) -+ odm_hw_setting_8821a(dm); -+#endif -+ -+#if 0 /* TODO: implementation done but may not work and do nothing with current flags. Commenting the code to match previous version behavior*/ -+#if (RTL8814A_SUPPORT == 1) -+ if (dm->support_ic_type & ODM_RTL8814A) -+ phydm_hwsetting_8814a(dm); -+#endif -+#endif -+ -+#if (RTL8822B_SUPPORT == 1) -+ if (dm->support_ic_type & ODM_RTL8822B) -+ phydm_hwsetting_8822b(dm); -+#endif -+ -+#if (RTL8812A_SUPPORT == 1) -+ if (dm->support_ic_type & ODM_RTL8812) -+ phydm_hwsetting_8812a(dm); -+#endif -+ -+#if (RTL8197F_SUPPORT == 1) -+ if (dm->support_ic_type & ODM_RTL8197F) -+ phydm_hwsetting_8197f(dm); -+#endif -+ -+#if (RTL8192F_SUPPORT == 1) -+ if (dm->support_ic_type & ODM_RTL8192F) -+ phydm_hwsetting_8192f(dm); -+#endif -+} -+ -+#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN)) -+u64 phydm_supportability_init_win( -+ void *dm_void) -+{ -+ struct dm_struct *dm = (struct dm_struct *)dm_void; -+ u64 support_ability = 0; -+ -+ switch (dm->support_ic_type) { -+/*@---------------N Series--------------------*/ -+#if (RTL8188E_SUPPORT) -+ case ODM_RTL8188E: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ /*ODM_BB_DYNAMIC_TXPWR |*/ -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR | -+ ODM_BB_PRIMARY_CCA; -+ break; -+#endif -+ -+#if (RTL8192E_SUPPORT) -+ case ODM_RTL8192E: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ /*ODM_BB_DYNAMIC_TXPWR |*/ -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR | -+ ODM_BB_PRIMARY_CCA; -+ break; -+#endif -+ -+#if (RTL8723B_SUPPORT) -+ case ODM_RTL8723B: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ /*ODM_BB_DYNAMIC_TXPWR |*/ -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR | -+ ODM_BB_PRIMARY_CCA; -+ break; -+#endif -+ -+#if (RTL8703B_SUPPORT) -+ case ODM_RTL8703B: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ /*ODM_BB_DYNAMIC_TXPWR |*/ -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR; -+ break; -+#endif -+ -+#if (RTL8723D_SUPPORT) -+ case ODM_RTL8723D: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ /*ODM_BB_DYNAMIC_TXPWR |*/ -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ ODM_BB_PWR_TRAIN | -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR; -+ break; -+#endif -+ -+#if (RTL8710B_SUPPORT) -+ case ODM_RTL8710B: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ /*ODM_BB_DYNAMIC_TXPWR |*/ -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ ODM_BB_PWR_TRAIN | -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR; -+ break; -+#endif -+ -+#if (RTL8188F_SUPPORT) -+ case ODM_RTL8188F: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ /*ODM_BB_DYNAMIC_TXPWR |*/ -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR; -+ break; -+#endif -+ -+#if (RTL8192F_SUPPORT) -+ case ODM_RTL8192F: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ ODM_BB_PWR_TRAIN | -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ADAPTIVE_SOML | -+ ODM_BB_ENV_MONITOR; -+ /*ODM_BB_LNA_SAT_CHK |*/ -+ /*ODM_BB_PRIMARY_CCA*/ -+ -+ break; -+#endif -+ -+/*@---------------AC Series-------------------*/ -+ -+#if (RTL8812A_SUPPORT || RTL8821A_SUPPORT) -+ case ODM_RTL8812: -+ case ODM_RTL8821: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ ODM_BB_DYNAMIC_TXPWR | -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR; -+ break; -+#endif -+ -+#if (RTL8814A_SUPPORT) -+ case ODM_RTL8814A: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ ODM_BB_DYNAMIC_TXPWR | -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR; -+ break; -+#endif -+ -+#if (RTL8822B_SUPPORT) -+ case ODM_RTL8822B: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ /*ODM_BB_DYNAMIC_TXPWR |*/ -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*ODM_BB_PWR_TRAIN |*/ -+ /*ODM_BB_ADAPTIVE_SOML |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR; -+ break; -+#endif -+ -+#if (RTL8821C_SUPPORT) -+ case ODM_RTL8821C: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ /*ODM_BB_DYNAMIC_TXPWR |*/ -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR; -+ break; -+#endif -+ -+/*@---------------JGR3 Series-------------------*/ -+ -+#if (RTL8822C_SUPPORT) -+ case ODM_RTL8822C: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ /* ODM_BB_DYNAMIC_TXPWR |*/ -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR; -+ break; -+#endif -+ -+#if (RTL8814B_SUPPORT) -+ case ODM_RTL8814B: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ /*ODM_BB_DYNAMIC_TXPWR |*/ -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ /*ODM_BB_CCK_PD |*/ -+ /*ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING; -+ /*ODM_BB_ENV_MONITOR;*/ -+ break; -+#endif -+ -+ default: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ /*ODM_BB_DYNAMIC_TXPWR |*/ -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR; -+ -+ pr_debug("[Warning] Supportability Init Warning !!!\n"); -+ break; -+ } -+ -+ return support_ability; -+} -+#endif -+ -+#if (DM_ODM_SUPPORT_TYPE & (ODM_CE)) -+u64 phydm_supportability_init_ce(void *dm_void) -+{ -+ struct dm_struct *dm = (struct dm_struct *)dm_void; -+ u64 support_ability = 0; -+ -+ switch (dm->support_ic_type) { -+/*@---------------N Series--------------------*/ -+#if (RTL8188E_SUPPORT) -+ case ODM_RTL8188E: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ /*@ODM_BB_DYNAMIC_TXPWR |*/ -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*@ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR | -+ ODM_BB_PRIMARY_CCA; -+ break; -+#endif -+ -+#if (RTL8192E_SUPPORT) -+ case ODM_RTL8192E: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ /*@ODM_BB_DYNAMIC_TXPWR |*/ -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*@ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR | -+ ODM_BB_PRIMARY_CCA; -+ break; -+#endif -+ -+#if (RTL8723B_SUPPORT) -+ case ODM_RTL8723B: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ /*@ODM_BB_DYNAMIC_TXPWR |*/ -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*@ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR | -+ ODM_BB_PRIMARY_CCA; -+ break; -+#endif -+ -+#if (RTL8703B_SUPPORT) -+ case ODM_RTL8703B: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ /*@ODM_BB_DYNAMIC_TXPWR |*/ -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*@ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR; -+ break; -+#endif -+ -+#if (RTL8723D_SUPPORT) -+ case ODM_RTL8723D: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ /*@ODM_BB_DYNAMIC_TXPWR |*/ -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ ODM_BB_PWR_TRAIN | -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR; -+ break; -+#endif -+ -+#if (RTL8710B_SUPPORT) -+ case ODM_RTL8710B: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ /*@ODM_BB_DYNAMIC_TXPWR |*/ -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*@ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR; -+ break; -+#endif -+ -+#if (RTL8188F_SUPPORT) -+ case ODM_RTL8188F: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ /*@ODM_BB_DYNAMIC_TXPWR |*/ -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*@ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR; -+ break; -+#endif -+ -+#if (RTL8192F_SUPPORT) -+ case ODM_RTL8192F: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ ODM_BB_PWR_TRAIN | -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ /*@ODM_BB_ADAPTIVE_SOML |*/ -+ ODM_BB_ENV_MONITOR; -+ /*@ODM_BB_LNA_SAT_CHK |*/ -+ /*@ODM_BB_PRIMARY_CCA*/ -+ break; -+#endif -+/*@---------------AC Series-------------------*/ -+ -+#if (RTL8812A_SUPPORT || RTL8821A_SUPPORT) -+ case ODM_RTL8812: -+ case ODM_RTL8821: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ /*@ODM_BB_DYNAMIC_TXPWR |*/ -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*@ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR; -+ break; -+#endif -+ -+#if (RTL8814A_SUPPORT) -+ case ODM_RTL8814A: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ /*@ODM_BB_DYNAMIC_TXPWR |*/ -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*@ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR; -+ break; -+#endif -+ -+#if (RTL8822B_SUPPORT) -+ case ODM_RTL8822B: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ /*@ODM_BB_DYNAMIC_TXPWR |*/ -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*@ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR; -+ break; -+#endif -+ -+#if (RTL8821C_SUPPORT) -+ case ODM_RTL8821C: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ /*@ODM_BB_DYNAMIC_TXPWR |*/ -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*@ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR; -+ break; -+#endif -+ -+/*@---------------JGR3 Series-------------------*/ -+ -+#if (RTL8822C_SUPPORT) -+ case ODM_RTL8822C: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ /* ODM_BB_DYNAMIC_TXPWR |*/ -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR; -+ break; -+#endif -+ -+#if (RTL8814B_SUPPORT) -+ case ODM_RTL8814B: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ /*@ODM_BB_DYNAMIC_TXPWR |*/ -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR; -+ /*ODM_BB_CCK_PD |*/ -+ /*@ODM_BB_PWR_TRAIN |*/ -+ /*ODM_BB_RATE_ADAPTIVE |*/ -+ /*ODM_BB_CFO_TRACKING |*/ -+ /*ODM_BB_ENV_MONITOR;*/ -+ break; -+#endif -+ -+ default: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ /*@ODM_BB_DYNAMIC_TXPWR |*/ -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*@ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR; -+ -+ pr_debug("[Warning] Supportability Init Warning !!!\n"); -+ break; -+ } -+ -+ return support_ability; -+} -+#endif -+ -+#if (DM_ODM_SUPPORT_TYPE & (ODM_AP)) -+u64 phydm_supportability_init_ap( -+ void *dm_void) -+{ -+ struct dm_struct *dm = (struct dm_struct *)dm_void; -+ u64 support_ability = 0; -+ -+ switch (dm->support_ic_type) { -+/*@---------------N Series--------------------*/ -+#if (RTL8188E_SUPPORT) -+ case ODM_RTL8188E: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR | -+ ODM_BB_PRIMARY_CCA; -+ break; -+#endif -+ -+#if (RTL8192E_SUPPORT) -+ case ODM_RTL8192E: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR | -+ ODM_BB_PRIMARY_CCA; -+ break; -+#endif -+ -+#if (RTL8723B_SUPPORT) -+ case ODM_RTL8723B: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR; -+ break; -+#endif -+ -+#if (RTL8198F_SUPPORT || RTL8197F_SUPPORT) -+ case ODM_RTL8198F: -+ support_ability |= -+ /*ODM_BB_DIG |*/ -+ ODM_BB_RA_MASK | -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR; -+ /*ODM_BB_CCK_PD |*/ -+ /*ODM_BB_PWR_TRAIN |*/ -+ /*ODM_BB_RATE_ADAPTIVE |*/ -+ /*ODM_BB_CFO_TRACKING |*/ -+ /*ODM_BB_ADAPTIVE_SOML |*/ -+ /*ODM_BB_ENV_MONITOR |*/ -+ /*ODM_BB_LNA_SAT_CHK |*/ -+ /*ODM_BB_PRIMARY_CCA;*/ -+ break; -+ case ODM_RTL8197F: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ADAPTIVE_SOML | -+ ODM_BB_ENV_MONITOR | -+ ODM_BB_LNA_SAT_CHK | -+ ODM_BB_PRIMARY_CCA; -+ break; -+#endif -+ -+#if (RTL8192F_SUPPORT) -+ case ODM_RTL8192F: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ /*ODM_BB_CFO_TRACKING |*/ -+ ODM_BB_ADAPTIVE_SOML | -+ /*ODM_BB_ENV_MONITOR |*/ -+ /*ODM_BB_LNA_SAT_CHK |*/ -+ /*ODM_BB_PRIMARY_CCA |*/ -+ 0; -+ break; -+#endif -+ -+/*@---------------AC Series-------------------*/ -+ -+#if (RTL8881A_SUPPORT) -+ case ODM_RTL8881A: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR; -+ break; -+#endif -+ -+#if (RTL8814A_SUPPORT) -+ case ODM_RTL8814A: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR; -+ break; -+#endif -+ -+#if (RTL8822B_SUPPORT) -+ case ODM_RTL8822B: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*ODM_BB_PWR_TRAIN |*/ -+ /*ODM_BB_ADAPTIVE_SOML |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR; -+ break; -+#endif -+ -+#if (RTL8821C_SUPPORT) -+ case ODM_RTL8821C: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR; -+ -+ break; -+#endif -+ -+/*@---------------JGR3 Series-------------------*/ -+ -+#if (RTL8814B_SUPPORT) -+ case ODM_RTL8814B: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR; -+ /*ODM_BB_CCK_PD |*/ -+ /*ODM_BB_PWR_TRAIN |*/ -+ /*ODM_BB_RATE_ADAPTIVE |*/ -+ /*ODM_BB_CFO_TRACKING |*/ -+ /*ODM_BB_ENV_MONITOR;*/ -+ break; -+#endif -+ -+ default: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR; -+ -+ pr_debug("[Warning] Supportability Init Warning !!!\n"); -+ break; -+ } -+ -+#if 0 -+ /*@[Config Antenna Diveristy]*/ -+ if (*dm->enable_antdiv) -+ support_ability |= ODM_BB_ANT_DIV; -+ -+ /*@[Config Adaptivity]*/ -+ if (*dm->enable_adaptivity) -+ support_ability |= ODM_BB_ADAPTIVITY; -+#endif -+ -+ return support_ability; -+} -+#endif -+ -+#if (DM_ODM_SUPPORT_TYPE & (ODM_IOT)) -+u64 phydm_supportability_init_iot( -+ void *dm_void) -+{ -+ struct dm_struct *dm = (struct dm_struct *)dm_void; -+ u64 support_ability = 0; -+ -+ switch (dm->support_ic_type) { -+#if (RTL8710B_SUPPORT) -+ case ODM_RTL8710B: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ /*ODM_BB_DYNAMIC_TXPWR |*/ -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR; -+ break; -+#endif -+ -+#if (RTL8195A_SUPPORT) -+ case ODM_RTL8195A: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ /*ODM_BB_DYNAMIC_TXPWR |*/ -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR; -+ break; -+#endif -+ -+#if (RTL8195B_SUPPORT) -+ case ODM_RTL8195B: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ /*ODM_BB_DYNAMIC_TXPWR |*/ -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING; -+ /*ODM_BB_ENV_MONITOR*/ -+ break; -+#endif -+ -+#if (RTL8721D_SUPPORT) -+ case ODM_RTL8721D: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ /*ODM_BB_DYNAMIC_TXPWR |*/ -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR; -+ break; -+#endif -+ -+ default: -+ support_ability |= -+ ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ /*ODM_BB_DYNAMIC_TXPWR |*/ -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ /*ODM_BB_PWR_TRAIN |*/ -+ ODM_BB_RATE_ADAPTIVE | -+ ODM_BB_CFO_TRACKING | -+ ODM_BB_ENV_MONITOR; -+ -+ pr_debug("[Warning] Supportability Init Warning !!!\n"); -+ break; -+ } -+ -+ return support_ability; -+} -+#endif -+ -+void phydm_fwoffload_ability_init(struct dm_struct *dm, -+ enum phydm_offload_ability offload_ability) -+{ -+ switch (offload_ability) { -+ case PHYDM_PHY_PARAM_OFFLOAD: -+ if (dm->support_ic_type & -+ (ODM_RTL8814A | ODM_RTL8822B | ODM_RTL8821C)) -+ dm->fw_offload_ability |= PHYDM_PHY_PARAM_OFFLOAD; -+ break; -+ -+ case PHYDM_RF_IQK_OFFLOAD: -+ dm->fw_offload_ability |= PHYDM_RF_IQK_OFFLOAD; -+ break; -+ -+ default: -+ PHYDM_DBG(dm, ODM_COMP_INIT, "fwofflad, wrong init type!!\n"); -+ break; -+ } -+ -+ PHYDM_DBG(dm, ODM_COMP_INIT, "fw_offload_ability = %x\n", -+ dm->fw_offload_ability); -+} -+ -+void phydm_fwoffload_ability_clear(struct dm_struct *dm, -+ enum phydm_offload_ability offload_ability) -+{ -+ switch (offload_ability) { -+ case PHYDM_PHY_PARAM_OFFLOAD: -+ if (dm->support_ic_type & -+ (ODM_RTL8814A | ODM_RTL8822B | ODM_RTL8821C)) -+ dm->fw_offload_ability &= (~PHYDM_PHY_PARAM_OFFLOAD); -+ break; -+ -+ case PHYDM_RF_IQK_OFFLOAD: -+ dm->fw_offload_ability &= (~PHYDM_RF_IQK_OFFLOAD); -+ break; -+ -+ default: -+ PHYDM_DBG(dm, ODM_COMP_INIT, "fwofflad, wrong init type!!\n"); -+ break; -+ } -+ -+ PHYDM_DBG(dm, ODM_COMP_INIT, "fw_offload_ability = %x\n", -+ dm->fw_offload_ability); -+} -+ -+void phydm_supportability_init(void *dm_void) -+{ -+ struct dm_struct *dm = (struct dm_struct *)dm_void; -+ u64 support_ability; -+ -+ if (*dm->mp_mode) { -+ support_ability = 0; -+ } else { -+ #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN)) -+ support_ability = phydm_supportability_init_win(dm); -+ #elif (DM_ODM_SUPPORT_TYPE & (ODM_AP)) -+ support_ability = phydm_supportability_init_ap(dm); -+ #elif(DM_ODM_SUPPORT_TYPE & (ODM_CE)) -+ support_ability = phydm_supportability_init_ce(dm); -+ #elif(DM_ODM_SUPPORT_TYPE & (ODM_IOT)) -+ support_ability = phydm_supportability_init_iot(dm); -+ #endif -+ -+ /*@[Config Antenna Diversity]*/ -+ if (IS_FUNC_EN(dm->enable_antdiv)) -+ support_ability |= ODM_BB_ANT_DIV; -+ -+ /*@[Config TXpath Diversity]*/ -+ if (IS_FUNC_EN(dm->enable_pathdiv)) -+ support_ability |= ODM_BB_PATH_DIV; -+ -+ /*@[Config Adaptive SOML]*/ -+ if (IS_FUNC_EN(dm->en_adap_soml)) -+ support_ability |= ODM_BB_ADAPTIVE_SOML; -+ -+ /* @[Config Adaptivity]*/ -+ if (IS_FUNC_EN(dm->enable_adaptivity)) -+ support_ability |= ODM_BB_ADAPTIVITY; -+ } -+ odm_cmn_info_init(dm, ODM_CMNINFO_ABILITY, support_ability); -+ PHYDM_DBG(dm, ODM_COMP_INIT, "IC=0x%x, mp=%d, Supportability=0x%llx\n", -+ dm->support_ic_type, *dm->mp_mode, dm->support_ability); -+} -+ -+void phydm_rfe_init(void *dm_void) -+{ -+ struct dm_struct *dm = (struct dm_struct *)dm_void; -+ -+ PHYDM_DBG(dm, ODM_COMP_INIT, "RFE_Init\n"); -+#if (RTL8822B_SUPPORT == 1) -+ if (dm->support_ic_type == ODM_RTL8822B) -+ phydm_rfe_8822b_init(dm); -+#endif -+} -+ -+void phydm_dm_early_init(struct dm_struct *dm) -+{ -+ -+} -+ -+void odm_dm_init(struct dm_struct *dm) -+{ -+ halrf_init(dm); -+ phydm_supportability_init(dm); -+ phydm_rfe_init(dm); -+ phydm_common_info_self_init(dm); -+ phydm_rx_phy_status_init(dm); -+#ifdef PHYDM_AUTO_DEGBUG -+ phydm_auto_dbg_engine_init(dm); -+#endif -+ phydm_dig_init(dm); -+#ifdef PHYDM_SUPPORT_CCKPD -+ phydm_cck_pd_init(dm); -+#endif -+ phydm_env_monitor_init(dm); -+ phydm_adaptivity_init(dm); -+ phydm_ra_info_init(dm); -+ phydm_rssi_monitor_init(dm); -+ phydm_cfo_tracking_init(dm); -+ phydm_rf_init(dm); -+ phydm_dc_cancellation(dm); -+#ifdef PHYDM_TXA_CALIBRATION -+ phydm_txcurrentcalibration(dm); -+ phydm_get_pa_bias_offset(dm); -+#endif -+#ifdef CONFIG_PHYDM_ANTENNA_DIVERSITY -+ odm_antenna_diversity_init(dm); -+#endif -+#ifdef CONFIG_ADAPTIVE_SOML -+ phydm_adaptive_soml_init(dm); -+#endif -+#ifdef CONFIG_PATH_DIVERSITY -+ phydm_tx_path_diversity_init(dm); -+#endif -+#ifdef CONFIG_DYNAMIC_TX_TWR -+ phydm_dynamic_tx_power_init(dm); -+#endif -+#if (PHYDM_LA_MODE_SUPPORT == 1) -+ adc_smp_init(dm); -+#endif -+ -+#ifdef PHYDM_BEAMFORMING_VERSION1 -+ phydm_beamforming_init(dm); -+#endif -+ -+#if (RTL8188E_SUPPORT == 1) -+ odm_ra_info_init_all(dm); -+#endif -+#ifdef PHYDM_PRIMARY_CCA -+ phydm_primary_cca_init(dm); -+#endif -+#ifdef CONFIG_PSD_TOOL -+ phydm_psd_init(dm); -+#endif -+ -+#ifdef CONFIG_SMART_ANTENNA -+ phydm_smt_ant_init(dm); -+#endif -+#ifdef PHYDM_LNA_SAT_CHK_SUPPORT -+ phydm_lna_sat_check_init(dm); -+#endif -+#ifdef CONFIG_MCC_DM -+ #if (RTL8822B_SUPPORT == 1) -+ phydm_mcc_init(dm); -+ #endif -+#endif -+} -+ -+void odm_dm_reset(struct dm_struct *dm) -+{ -+ struct phydm_dig_struct *dig_t = &dm->dm_dig_table; -+ -+ #ifdef CONFIG_PHYDM_ANTENNA_DIVERSITY -+ odm_ant_div_reset(dm); -+ #endif -+ phydm_set_edcca_threshold_api(dm, dig_t->cur_ig_value); -+} -+ -+void phydm_supportability_en(void *dm_void, char input[][16], u32 *_used, -+ char *output, u32 *_out_len) -+{ -+ struct dm_struct *dm = (struct dm_struct *)dm_void; -+ u32 dm_value[10] = {0}; -+ u64 pre_support_ability, one = 1; -+ u64 comp = 0; -+ u32 used = *_used; -+ u32 out_len = *_out_len; -+ u8 i; -+ -+ for (i = 0; i < 5; i++) { -+ if (input[i + 1]) -+ PHYDM_SSCANF(input[i + 1], DCMD_DECIMAL, &dm_value[i]); -+ } -+ -+ pre_support_ability = dm->support_ability; -+ comp = dm->support_ability; -+ -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "\n================================\n"); -+ -+ if (dm_value[0] == 100) { -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "[Supportability] PhyDM Selection\n"); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "================================\n"); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "00. (( %s ))DIG\n", -+ ((comp & ODM_BB_DIG) ? ("V") : ("."))); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "01. (( %s ))RA_MASK\n", -+ ((comp & ODM_BB_RA_MASK) ? ("V") : ("."))); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "02. (( %s ))DYN_TXPWR\n", -+ ((comp & ODM_BB_DYNAMIC_TXPWR) ? ("V") : ("."))); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "03. (( %s ))FA_CNT\n", -+ ((comp & ODM_BB_FA_CNT) ? ("V") : ("."))); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "04. (( %s ))RSSI_MNTR\n", -+ ((comp & ODM_BB_RSSI_MONITOR) ? ("V") : ("."))); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "05. (( %s ))CCK_PD\n", -+ ((comp & ODM_BB_CCK_PD) ? ("V") : ("."))); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "06. (( %s ))ANT_DIV\n", -+ ((comp & ODM_BB_ANT_DIV) ? ("V") : ("."))); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "07. (( %s ))SMT_ANT\n", -+ ((comp & ODM_BB_SMT_ANT) ? ("V") : ("."))); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "08. (( %s ))PWR_TRAIN\n", -+ ((comp & ODM_BB_PWR_TRAIN) ? ("V") : ("."))); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "09. (( %s ))RA\n", -+ ((comp & ODM_BB_RATE_ADAPTIVE) ? ("V") : ("."))); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "10. (( %s ))PATH_DIV\n", -+ ((comp & ODM_BB_PATH_DIV) ? ("V") : ("."))); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "11. (( %s ))DFS\n", -+ ((comp & ODM_BB_DFS) ? ("V") : ("."))); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "12. (( %s ))DYN_ARFR\n", -+ ((comp & ODM_BB_DYNAMIC_ARFR) ? ("V") : ("."))); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "13. (( %s ))ADAPTIVITY\n", -+ ((comp & ODM_BB_ADAPTIVITY) ? ("V") : ("."))); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "14. (( %s ))CFO_TRACK\n", -+ ((comp & ODM_BB_CFO_TRACKING) ? ("V") : ("."))); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "15. (( %s ))ENV_MONITOR\n", -+ ((comp & ODM_BB_ENV_MONITOR) ? ("V") : ("."))); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "16. (( %s ))PRI_CCA\n", -+ ((comp & ODM_BB_PRIMARY_CCA) ? ("V") : ("."))); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "17. (( %s ))ADPTV_SOML\n", -+ ((comp & ODM_BB_ADAPTIVE_SOML) ? ("V") : ("."))); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "18. (( %s ))LNA_SAT_CHK\n", -+ ((comp & ODM_BB_LNA_SAT_CHK) ? ("V") : ("."))); -+ -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "================================\n"); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "[Supportability] PhyDM offload ability\n"); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "================================\n"); -+ -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "00. (( %s ))PHY PARAM OFFLOAD\n", -+ ((dm->fw_offload_ability & PHYDM_PHY_PARAM_OFFLOAD) ? -+ ("V") : ("."))); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "01. (( %s ))RF IQK OFFLOAD\n", -+ ((dm->fw_offload_ability & PHYDM_RF_IQK_OFFLOAD) ? -+ ("V") : ("."))); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "================================\n"); -+ -+ } else if (dm_value[0] == 101) { -+ dm->support_ability = 0; -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "Disable all support_ability components\n"); -+ } else { -+ if (dm_value[1] == 1) { /* @enable */ -+ dm->support_ability |= (one << dm_value[0]); -+ } else if (dm_value[1] == 2) {/* @disable */ -+ dm->support_ability &= ~(one << dm_value[0]); -+ } else { -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "[Warning!!!] 1:enable, 2:disable\n"); -+ } -+ } -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "pre-supportability = 0x%llx\n", pre_support_ability); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "Cur-supportability = 0x%llx\n", dm->support_ability); -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "================================\n"); -+ -+ *_used = used; -+ *_out_len = out_len; -+} -+ -+void phydm_watchdog_lps_32k(struct dm_struct *dm) -+{ -+ PHYDM_DBG(dm, DBG_COMMON_FLOW, "%s ======>\n", __func__); -+ -+ phydm_common_info_self_update(dm); -+ phydm_rssi_monitor_check(dm); -+ phydm_dig_lps_32k(dm); -+ phydm_common_info_self_reset(dm); -+} -+ -+void phydm_watchdog_lps(struct dm_struct *dm) -+{ -+#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE | ODM_IOT)) -+ PHYDM_DBG(dm, DBG_COMMON_FLOW, "%s ======>\n", __func__); -+ -+ phydm_common_info_self_update(dm); -+ phydm_rssi_monitor_check(dm); -+ phydm_basic_dbg_message(dm); -+ phydm_receiver_blocking(dm); -+ phydm_false_alarm_counter_statistics(dm); -+ phydm_dig_by_rssi_lps(dm); -+ #ifdef PHYDM_SUPPORT_CCKPD -+ phydm_cck_pd_th(dm); -+ #endif -+ phydm_adaptivity(dm); -+ #if (DM_ODM_SUPPORT_TYPE & (ODM_CE)) -+ #ifdef CONFIG_PHYDM_ANTENNA_DIVERSITY -+ /*@enable AntDiv in PS mode, request from SD4 Jeff*/ -+ odm_antenna_diversity(dm); -+ #endif -+ #endif -+ phydm_common_info_self_reset(dm); -+#endif -+} -+ -+void phydm_watchdog_mp(struct dm_struct *dm) -+{ -+} -+ -+void phydm_pause_dm_watchdog(void *dm_void, enum phydm_pause_type pause_type) -+{ -+ struct dm_struct *dm = (struct dm_struct *)dm_void; -+ -+ if (pause_type == PHYDM_PAUSE) { -+ dm->disable_phydm_watchdog = 1; -+ PHYDM_DBG(dm, ODM_COMP_API, "PHYDM Stop\n"); -+ } else { -+ dm->disable_phydm_watchdog = 0; -+ PHYDM_DBG(dm, ODM_COMP_API, "PHYDM Start\n"); -+ } -+} -+ -+u8 phydm_pause_func(void *dm_void, enum phydm_func_idx pause_func, -+ enum phydm_pause_type pause_type, -+ enum phydm_pause_level pause_lv, u8 val_lehgth, -+ u32 *val_buf) -+{ -+ struct dm_struct *dm = (struct dm_struct *)dm_void; -+ struct phydm_func_poiner *func_t = &dm->phydm_func_handler; -+ s8 *pause_lv_pre = &dm->s8_dummy; -+ u32 *bkp_val = &dm->u32_dummy; -+ u32 ori_val[5] = {0}; -+ u64 pause_func_bitmap = (u64)BIT(pause_func); -+ u8 i = 0; -+ u8 en_2rcca = 0; -+ u8 en_bw40m = 0; -+ u8 pause_result = PAUSE_FAIL; -+ -+ PHYDM_DBG(dm, ODM_COMP_API, "\n"); -+ PHYDM_DBG(dm, ODM_COMP_API, "[%s][%s] LV=%d, Len=%d\n", __func__, -+ ((pause_type == PHYDM_PAUSE) ? "Pause" : -+ ((pause_type == PHYDM_RESUME) ? "Resume" : "Pause no_set")), -+ pause_lv, val_lehgth); -+ -+ if (pause_lv >= PHYDM_PAUSE_MAX_NUM) { -+ PHYDM_DBG(dm, ODM_COMP_API, "[WARNING]Wrong LV=%d\n", pause_lv); -+ return PAUSE_FAIL; -+ } -+ -+ if (pause_func == F00_DIG) { -+ PHYDM_DBG(dm, ODM_COMP_API, "[DIG]\n"); -+ -+ if (val_lehgth != 1) { -+ PHYDM_DBG(dm, ODM_COMP_API, "[WARNING] length != 1\n"); -+ return PAUSE_FAIL; -+ } -+ -+ ori_val[0] = (u32)(dm->dm_dig_table.cur_ig_value); -+ pause_lv_pre = &dm->pause_lv_table.lv_dig; -+ bkp_val = (u32 *)(&dm->dm_dig_table.rvrt_val); -+ /*@function pointer hook*/ -+ func_t->pause_phydm_handler = phydm_set_dig_val; -+ -+#ifdef PHYDM_SUPPORT_CCKPD -+ } else if (pause_func == F05_CCK_PD) { -+ PHYDM_DBG(dm, ODM_COMP_API, "[CCK_PD]\n"); -+ -+ if (val_lehgth != 1) { -+ PHYDM_DBG(dm, ODM_COMP_API, "[WARNING] length != 1\n"); -+ return PAUSE_FAIL; -+ } -+ -+ ori_val[0] = (u32)dm->dm_cckpd_table.cck_pd_lv; -+ pause_lv_pre = &dm->pause_lv_table.lv_cckpd; -+ bkp_val = (u32 *)(&dm->dm_cckpd_table.rvrt_val); -+ /*@function pointer hook*/ -+ func_t->pause_phydm_handler = phydm_set_cckpd_val; -+#endif -+ -+#ifdef CONFIG_PHYDM_ANTENNA_DIVERSITY -+ } else if (pause_func == F06_ANT_DIV) { -+ PHYDM_DBG(dm, ODM_COMP_API, "[AntDiv]\n"); -+ -+ if (val_lehgth != 1) { -+ PHYDM_DBG(dm, ODM_COMP_API, "[WARNING] length != 1\n"); -+ return PAUSE_FAIL; -+ } -+ /*@default antenna*/ -+ ori_val[0] = (u32)(dm->dm_fat_table.rx_idle_ant); -+ pause_lv_pre = &dm->pause_lv_table.lv_antdiv; -+ bkp_val = (u32 *)(&dm->dm_fat_table.rvrt_val); -+ /*@function pointer hook*/ -+ func_t->pause_phydm_handler = phydm_set_antdiv_val; -+ -+#endif -+#ifdef PHYDM_SUPPORT_ADAPTIVITY -+ } else if (pause_func == F13_ADPTVTY) { -+ PHYDM_DBG(dm, ODM_COMP_API, "[Adaptivity]\n"); -+ -+ if (val_lehgth != 2) { -+ PHYDM_DBG(dm, ODM_COMP_API, "[WARNING] length != 2\n"); -+ return PAUSE_FAIL; -+ } -+ -+ ori_val[0] = (u32)(dm->adaptivity.th_l2h); /*th_l2h*/ -+ ori_val[1] = (u32)(dm->adaptivity.th_h2l); /*th_h2l*/ -+ pause_lv_pre = &dm->pause_lv_table.lv_adapt; -+ bkp_val = (u32 *)(&dm->adaptivity.rvrt_val); -+ /*@function pointer hook*/ -+ func_t->pause_phydm_handler = phydm_set_edcca_val; -+ -+#endif -+#ifdef CONFIG_ADAPTIVE_SOML -+ } else if (pause_func == F17_ADPTV_SOML) { -+ PHYDM_DBG(dm, ODM_COMP_API, "[AD-SOML]\n"); -+ -+ if (val_lehgth != 1) { -+ PHYDM_DBG(dm, ODM_COMP_API, "[WARNING] length != 1\n"); -+ return PAUSE_FAIL; -+ } -+ /*SOML_ON/OFF*/ -+ ori_val[0] = (u32)(dm->dm_soml_table.soml_on_off); -+ -+ pause_lv_pre = &dm->pause_lv_table.lv_adsl; -+ bkp_val = (u32 *)(&dm->dm_soml_table.rvrt_val); -+ /*@function pointer hook*/ -+ func_t->pause_phydm_handler = phydm_set_adsl_val; -+ -+#endif -+ } else { -+ PHYDM_DBG(dm, ODM_COMP_API, "[WARNING] error func idx\n"); -+ return PAUSE_FAIL; -+ } -+ -+ PHYDM_DBG(dm, ODM_COMP_API, "Pause_LV{new , pre} = {%d ,%d}\n", -+ pause_lv, *pause_lv_pre); -+ -+ if (pause_type == PHYDM_PAUSE || pause_type == PHYDM_PAUSE_NO_SET) { -+ if (pause_lv <= *pause_lv_pre) { -+ PHYDM_DBG(dm, ODM_COMP_API, -+ "[PAUSE FAIL] Pre_LV >= Curr_LV\n"); -+ return PAUSE_FAIL; -+ } -+ -+ if (!(dm->pause_ability & pause_func_bitmap)) { -+ for (i = 0; i < val_lehgth; i++) -+ bkp_val[i] = ori_val[i]; -+ } -+ -+ dm->pause_ability |= pause_func_bitmap; -+ PHYDM_DBG(dm, ODM_COMP_API, "pause_ability=0x%llx\n", -+ dm->pause_ability); -+ -+ if (pause_type == PHYDM_PAUSE) { -+ for (i = 0; i < val_lehgth; i++) -+ PHYDM_DBG(dm, ODM_COMP_API, -+ "[PAUSE SUCCESS] val_idx[%d]{New, Ori}={0x%x, 0x%x}\n", -+ i, val_buf[i], bkp_val[i]); -+ func_t->pause_phydm_handler(dm, val_buf, val_lehgth); -+ } else { -+ for (i = 0; i < val_lehgth; i++) -+ PHYDM_DBG(dm, ODM_COMP_API, -+ "[PAUSE NO Set: SUCCESS] val_idx[%d]{Ori}={0x%x}\n", -+ i, bkp_val[i]); -+ } -+ -+ *pause_lv_pre = pause_lv; -+ pause_result = PAUSE_SUCCESS; -+ -+ } else if (pause_type == PHYDM_RESUME) { -+ if ((dm->pause_ability & pause_func_bitmap) == 0) { -+ PHYDM_DBG(dm, ODM_COMP_API, -+ "[RESUME] No Need to Revert\n"); -+ return PAUSE_SUCCESS; -+ } -+ -+ dm->pause_ability &= ~pause_func_bitmap; -+ PHYDM_DBG(dm, ODM_COMP_API, "pause_ability=0x%llx\n", -+ dm->pause_ability); -+ -+ *pause_lv_pre = PHYDM_PAUSE_RELEASE; -+ -+ for (i = 0; i < val_lehgth; i++) { -+ PHYDM_DBG(dm, ODM_COMP_API, -+ "[RESUME] val_idx[%d]={0x%x}\n", i, -+ bkp_val[i]); -+ } -+ -+ func_t->pause_phydm_handler(dm, bkp_val, val_lehgth); -+ -+ pause_result = PAUSE_SUCCESS; -+ } else { -+ PHYDM_DBG(dm, ODM_COMP_API, "[WARNING] error pause_type\n"); -+ pause_result = PAUSE_FAIL; -+ } -+ return pause_result; -+} -+ -+void phydm_pause_func_console(void *dm_void, char input[][16], u32 *_used, -+ char *output, u32 *_out_len) -+{ -+ struct dm_struct *dm = (struct dm_struct *)dm_void; -+ char help[] = "-h"; -+ u32 var1[10] = {0}; -+ u32 used = *_used; -+ u32 out_len = *_out_len; -+ u32 i; -+ u8 length = 0; -+ u32 buf[5] = {0}; -+ u8 set_result = 0; -+ enum phydm_func_idx func = 0; -+ enum phydm_pause_type type = 0; -+ enum phydm_pause_level lv = 0; -+ -+ if ((strcmp(input[1], help) == 0)) { -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "{Func} {1:pause,2:pause no set 3:Resume} {lv:0~3} Val[5:0]\n"); -+ -+ goto out; -+ } -+ -+ for (i = 0; i < 10; i++) { -+ if (input[i + 1]) -+ PHYDM_SSCANF(input[i + 1], DCMD_HEX, &var1[i]); -+ } -+ -+ func = (enum phydm_func_idx)var1[0]; -+ type = (enum phydm_pause_type)var1[1]; -+ lv = (enum phydm_pause_level)var1[2]; -+ -+ for (i = 0; i < 5; i++) -+ buf[i] = var1[3 + i]; -+ -+ if (func == F00_DIG) { -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "[DIG]\n"); -+ length = 1; -+ -+ } else if (func == F05_CCK_PD) { -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "[CCK_PD]\n"); -+ length = 1; -+ } else if (func == F06_ANT_DIV) { -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "[Ant_Div]\n"); -+ length = 1; -+ } else if (func == F13_ADPTVTY) { -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "[Adaptivity]\n"); -+ length = 2; -+ } else if (func == F17_ADPTV_SOML) { -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "[ADSL]\n"); -+ length = 1; -+ } else { -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "[Set Function Error]\n"); -+ length = 0; -+ } -+ -+ if (length != 0) { -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "{%s, lv=%d} val = %d, %d}\n", -+ ((type == PHYDM_PAUSE) ? "Pause" : -+ ((type == PHYDM_RESUME) ? "Resume" : "Pause no_set")), -+ lv, var1[3], var1[4]); -+ -+ set_result = phydm_pause_func(dm, func, type, lv, length, buf); -+ } -+ -+ PDM_SNPF(out_len, used, output + used, out_len - used, -+ "set_result = %d\n", set_result); -+ -+out: -+ *_used = used; -+ *_out_len = out_len; -+} -+ -+u8 phydm_stop_dm_watchdog_check(void *dm_void) -+{ -+ struct dm_struct *dm = (struct dm_struct *)dm_void; -+ -+ if (dm->disable_phydm_watchdog == 1) { -+ PHYDM_DBG(dm, DBG_COMMON_FLOW, "Disable phydm\n"); -+ return true; -+ } else { -+ return false; -+ } -+} -+ -+void phydm_watchdog(struct dm_struct *dm) -+{ -+ PHYDM_DBG(dm, DBG_COMMON_FLOW, "%s ======>\n", __func__); -+ -+ phydm_common_info_self_update(dm); -+ phydm_phy_info_update(dm); -+ phydm_rssi_monitor_check(dm); -+ phydm_basic_dbg_message(dm); -+ phydm_dm_summary(dm, FIRST_MACID); -+#ifdef PHYDM_AUTO_DEGBUG -+ phydm_auto_dbg_engine(dm); -+#endif -+ phydm_receiver_blocking(dm); -+ -+ if (phydm_stop_dm_watchdog_check(dm) == true) -+ return; -+ -+ phydm_hw_setting(dm); -+ -+ #ifdef PHYDM_TDMA_DIG_SUPPORT -+ if (dm->original_dig_restore == 0) -+ phydm_tdma_dig_timer_check(dm); -+ else -+ #endif -+ { -+ phydm_false_alarm_counter_statistics(dm); -+ phydm_noisy_detection(dm); -+ phydm_dig(dm); -+ #ifdef PHYDM_SUPPORT_CCKPD -+ phydm_cck_pd_th(dm); -+ #endif -+ } -+ -+#ifdef PHYDM_POWER_TRAINING_SUPPORT -+ phydm_update_power_training_state(dm); -+#endif -+ phydm_adaptivity(dm); -+ phydm_ra_info_watchdog(dm); -+#ifdef CONFIG_PATH_DIVERSITY -+ phydm_tx_path_diversity(dm); -+#endif -+ phydm_cfo_tracking(dm); -+#ifdef CONFIG_DYNAMIC_TX_TWR -+ phydm_dynamic_tx_power(dm); -+#endif -+#ifdef CONFIG_PHYDM_ANTENNA_DIVERSITY -+ odm_antenna_diversity(dm); -+#endif -+#ifdef CONFIG_ADAPTIVE_SOML -+ phydm_adaptive_soml(dm); -+#endif -+ -+#ifdef PHYDM_BEAMFORMING_VERSION1 -+ phydm_beamforming_watchdog(dm); -+#endif -+ -+ halrf_watchdog(dm); -+#ifdef PHYDM_PRIMARY_CCA -+ phydm_primary_cca(dm); -+#endif -+#if (DM_ODM_SUPPORT_TYPE == ODM_CE) -+ odm_dtc(dm); -+#endif -+ -+ phydm_env_mntr_watchdog(dm); -+ -+#ifdef PHYDM_LNA_SAT_CHK_SUPPORT -+ phydm_lna_sat_chk_watchdog(dm); -+#endif -+#ifdef CONFIG_MCC_DM -+ #if (RTL8822B_SUPPORT == 1) -+ phydm_mcc_switch(dm); -+ #endif -+#endif -+ phydm_common_info_self_reset(dm); -+} -+ -+/*@ -+ * Init /.. Fixed HW value. Only init time. -+ */ -+void odm_cmn_info_init(struct dm_struct *dm, enum odm_cmninfo cmn_info, -+ u64 value) -+{ -+ /* This section is used for init value */ -+ switch (cmn_info) { -+ /* @Fixed ODM value. */ -+ case ODM_CMNINFO_ABILITY: -+ dm->support_ability = (u64)value; -+ break; -+ -+ case ODM_CMNINFO_RF_TYPE: -+ dm->rf_type = (u8)value; -+ break; -+ -+ case ODM_CMNINFO_PLATFORM: -+ dm->support_platform = (u8)value; -+ break; -+ -+ case ODM_CMNINFO_INTERFACE: -+ dm->support_interface = (u8)value; -+ break; -+ -+ case ODM_CMNINFO_IC_TYPE: -+ dm->support_ic_type = (u32)value; -+ break; -+ -+ case ODM_CMNINFO_CUT_VER: -+ dm->cut_version = (u8)value; -+ break; -+ -+ case ODM_CMNINFO_FAB_VER: -+ dm->fab_version = (u8)value; -+ break; -+ case ODM_CMNINFO_FW_VER: -+ dm->fw_version = (u8)value; -+ break; -+ case ODM_CMNINFO_FW_SUB_VER: -+ dm->fw_sub_version = (u8)value; -+ break; -+ case ODM_CMNINFO_RFE_TYPE: -+#if (RTL8821C_SUPPORT == 1) -+ if (dm->support_ic_type & ODM_RTL8821C) -+ dm->rfe_type_expand = (u8)value; -+ else -+#endif -+ dm->rfe_type = (u8)value; -+ phydm_init_hw_info_by_rfe(dm); -+ break; -+ -+ case ODM_CMNINFO_RF_ANTENNA_TYPE: -+ dm->ant_div_type = (u8)value; -+ break; -+ -+ case ODM_CMNINFO_WITH_EXT_ANTENNA_SWITCH: -+ dm->with_extenal_ant_switch = (u8)value; -+ break; -+ -+#ifdef CONFIG_PHYDM_ANTENNA_DIVERSITY -+ case ODM_CMNINFO_BE_FIX_TX_ANT: -+ dm->dm_fat_table.b_fix_tx_ant = (u8)value; -+ break; -+#endif -+ -+ case ODM_CMNINFO_BOARD_TYPE: -+ if (!dm->is_init_hw_info_by_rfe) -+ dm->board_type = (u8)value; -+ break; -+ -+ case ODM_CMNINFO_PACKAGE_TYPE: -+ if (!dm->is_init_hw_info_by_rfe) -+ dm->package_type = (u8)value; -+ break; -+ -+ case ODM_CMNINFO_EXT_LNA: -+ if (!dm->is_init_hw_info_by_rfe) -+ dm->ext_lna = (u8)value; -+ break; -+ -+ case ODM_CMNINFO_5G_EXT_LNA: -+ if (!dm->is_init_hw_info_by_rfe) -+ dm->ext_lna_5g = (u8)value; -+ break; -+ -+ case ODM_CMNINFO_EXT_PA: -+ if (!dm->is_init_hw_info_by_rfe) -+ dm->ext_pa = (u8)value; -+ break; -+ -+ case ODM_CMNINFO_5G_EXT_PA: -+ if (!dm->is_init_hw_info_by_rfe) -+ dm->ext_pa_5g = (u8)value; -+ break; -+ -+ case ODM_CMNINFO_GPA: -+ if (!dm->is_init_hw_info_by_rfe) -+ dm->type_gpa = (u16)value; -+ break; -+ -+ case ODM_CMNINFO_APA: -+ if (!dm->is_init_hw_info_by_rfe) -+ dm->type_apa = (u16)value; -+ break; -+ -+ case ODM_CMNINFO_GLNA: -+ if (!dm->is_init_hw_info_by_rfe) -+ dm->type_glna = (u16)value; -+ break; -+ -+ case ODM_CMNINFO_ALNA: -+ if (!dm->is_init_hw_info_by_rfe) -+ dm->type_alna = (u16)value; -+ break; -+ -+ case ODM_CMNINFO_EXT_TRSW: -+ if (!dm->is_init_hw_info_by_rfe) -+ dm->ext_trsw = (u8)value; -+ break; -+ case ODM_CMNINFO_EXT_LNA_GAIN: -+ dm->ext_lna_gain = (u8)value; -+ break; -+ case ODM_CMNINFO_PATCH_ID: -+ dm->iot_table.win_patch_id = (u8)value; -+ break; -+ case ODM_CMNINFO_BINHCT_TEST: -+ dm->is_in_hct_test = (boolean)value; -+ break; -+ case ODM_CMNINFO_BWIFI_TEST: -+ dm->wifi_test = (u8)value; -+ break; -+ case ODM_CMNINFO_SMART_CONCURRENT: -+ dm->is_dual_mac_smart_concurrent = (boolean)value; -+ break; -+#if (DM_ODM_SUPPORT_TYPE & (ODM_AP)) -+ case ODM_CMNINFO_CONFIG_BB_RF: -+ dm->config_bbrf = (boolean)value; -+ break; -+#endif -+ case ODM_CMNINFO_IQKPAOFF: -+ dm->rf_calibrate_info.is_iqk_pa_off = (boolean)value; -+ break; -+ case ODM_CMNINFO_REGRFKFREEENABLE: -+ dm->rf_calibrate_info.reg_rf_kfree_enable = (u8)value; -+ break; -+ case ODM_CMNINFO_RFKFREEENABLE: -+ dm->rf_calibrate_info.rf_kfree_enable = (u8)value; -+ break; -+ case ODM_CMNINFO_NORMAL_RX_PATH_CHANGE: -+ dm->normal_rx_path = (u8)value; -+ break; -+ case ODM_CMNINFO_EFUSE0X3D8: -+ dm->efuse0x3d8 = (u8)value; -+ break; -+ case ODM_CMNINFO_EFUSE0X3D7: -+ dm->efuse0x3d7 = (u8)value; -+ break; -+ case ODM_CMNINFO_ADVANCE_OTA: -+ dm->p_advance_ota = (u8)value; -+ break; -+ -+#ifdef CONFIG_PHYDM_DFS_MASTER -+ case ODM_CMNINFO_DFS_REGION_DOMAIN: -+ dm->dfs_region_domain = (u8)value; -+ break; -+#endif -+ case ODM_CMNINFO_SOFT_AP_SPECIAL_SETTING: -+ dm->soft_ap_special_setting = (u32)value; -+ break; -+ -+ case ODM_CMNINFO_X_CAP_SETTING: -+ dm->dm_cfo_track.crystal_cap_default = (u8)value; -+ break; -+ -+ case ODM_CMNINFO_DPK_EN: -+ /*@dm->dpk_en = (u1Byte)value;*/ -+ halrf_cmn_info_set(dm, HALRF_CMNINFO_DPK_EN, (u64)value); -+ break; -+ -+ case ODM_CMNINFO_HP_HWID: -+ dm->hp_hw_id = (boolean)value; -+ break; -+ default: -+ break; -+ } -+} -+ -+void odm_cmn_info_hook(struct dm_struct *dm, enum odm_cmninfo cmn_info, -+ void *value) -+{ -+ /* @Hook call by reference pointer. */ -+ switch (cmn_info) { -+ /* @Dynamic call by reference pointer. */ -+ case ODM_CMNINFO_TX_UNI: -+ dm->num_tx_bytes_unicast = (u64 *)value; -+ break; -+ -+ case ODM_CMNINFO_RX_UNI: -+ dm->num_rx_bytes_unicast = (u64 *)value; -+ break; -+ -+ case ODM_CMNINFO_BAND: -+ dm->band_type = (u8 *)value; -+ break; -+ -+ case ODM_CMNINFO_SEC_CHNL_OFFSET: -+ dm->sec_ch_offset = (u8 *)value; -+ break; -+ -+ case ODM_CMNINFO_SEC_MODE: -+ dm->security = (u8 *)value; -+ break; -+ -+ case ODM_CMNINFO_BW: -+ dm->band_width = (u8 *)value; -+ break; -+ -+ case ODM_CMNINFO_CHNL: -+ dm->channel = (u8 *)value; -+ break; -+ -+ case ODM_CMNINFO_SCAN: -+ dm->is_scan_in_process = (boolean *)value; -+ break; -+ -+ case ODM_CMNINFO_POWER_SAVING: -+ dm->is_power_saving = (boolean *)value; -+ break; -+ -+ case ODM_CMNINFO_TDMA: -+ dm->is_tdma = (boolean *)value; -+ break; -+ -+ case ODM_CMNINFO_ONE_PATH_CCA: -+ dm->one_path_cca = (u8 *)value; -+ break; -+ -+ case ODM_CMNINFO_DRV_STOP: -+ dm->is_driver_stopped = (boolean *)value; -+ break; -+ case ODM_CMNINFO_INIT_ON: -+ dm->pinit_adpt_in_progress = (boolean *)value; -+ break; -+ -+ case ODM_CMNINFO_ANT_TEST: -+ dm->antenna_test = (u8 *)value; -+ break; -+ -+ case ODM_CMNINFO_NET_CLOSED: -+ dm->is_net_closed = (boolean *)value; -+ break; -+ -+ case ODM_CMNINFO_FORCED_RATE: -+ dm->forced_data_rate = (u16 *)value; -+ break; -+ case ODM_CMNINFO_ANT_DIV: -+ dm->enable_antdiv = (u8 *)value; -+ break; -+ case ODM_CMNINFO_PATH_DIV: -+ dm->enable_pathdiv = (u8 *)value; -+ break; -+ case ODM_CMNINFO_ADAPTIVE_SOML: -+ dm->en_adap_soml = (u8 *)value; -+ break; -+ case ODM_CMNINFO_ADAPTIVITY: -+ dm->enable_adaptivity = (u8 *)value; -+ break; -+ -+ case ODM_CMNINFO_P2P_LINK: -+ dm->dm_dig_table.is_p2p_in_process = (u8 *)value; -+ break; -+ -+ case ODM_CMNINFO_IS1ANTENNA: -+ dm->is_1_antenna = (boolean *)value; -+ break; -+ -+ case ODM_CMNINFO_RFDEFAULTPATH: -+ dm->rf_default_path = (u8 *)value; -+ break; -+ -+ case ODM_CMNINFO_FCS_MODE: -+ dm->is_fcs_mode_enable = (boolean *)value; -+ break; -+ -+ case ODM_CMNINFO_HUBUSBMODE: -+ dm->hub_usb_mode = (u8 *)value; -+ break; -+ case ODM_CMNINFO_FWDWRSVDPAGEINPROGRESS: -+ dm->is_fw_dw_rsvd_page_in_progress = (boolean *)value; -+ break; -+ case ODM_CMNINFO_TX_TP: -+ dm->current_tx_tp = (u32 *)value; -+ break; -+ case ODM_CMNINFO_RX_TP: -+ dm->current_rx_tp = (u32 *)value; -+ break; -+ case ODM_CMNINFO_SOUNDING_SEQ: -+ dm->sounding_seq = (u8 *)value; -+ break; -+#ifdef CONFIG_PHYDM_DFS_MASTER -+ case ODM_CMNINFO_DFS_MASTER_ENABLE: -+ dm->dfs_master_enabled = (u8 *)value; -+ break; -+#endif -+ -+#ifdef CONFIG_PHYDM_ANTENNA_DIVERSITY -+ case ODM_CMNINFO_FORCE_TX_ANT_BY_TXDESC: -+ dm->dm_fat_table.p_force_tx_by_desc = (u8 *)value; -+ break; -+ case ODM_CMNINFO_SET_S0S1_DEFAULT_ANTENNA: -+ dm->dm_fat_table.p_default_s0_s1 = (u8 *)value; -+ break; -+ case ODM_CMNINFO_BF_ANTDIV_DECISION: -+ dm->dm_fat_table.is_no_csi_feedback = (boolean *)value; -+ break; -+#endif -+ -+ case ODM_CMNINFO_SOFT_AP_MODE: -+ dm->soft_ap_mode = (u32 *)value; -+ break; -+ case ODM_CMNINFO_MP_MODE: -+ dm->mp_mode = (u8 *)value; -+ break; -+ case ODM_CMNINFO_INTERRUPT_MASK: -+ dm->interrupt_mask = (u32 *)value; -+ break; -+ case ODM_CMNINFO_BB_OPERATION_MODE: -+ dm->bb_op_mode = (u8 *)value; -+ break; -+ default: -+ /*do nothing*/ -+ break; -+ } -+} -+ -+/*@ -+ * Update band/CHannel/.. The values are dynamic but non-per-packet. -+ */ -+void odm_cmn_info_update(struct dm_struct *dm, u32 cmn_info, u64 value) -+{ -+ /* This init variable may be changed in run time. */ -+ switch (cmn_info) { -+ case ODM_CMNINFO_LINK_IN_PROGRESS: -+ dm->is_link_in_process = (boolean)value; -+ break; -+ -+ case ODM_CMNINFO_ABILITY: -+ dm->support_ability = (u64)value; -+ break; -+ -+ case ODM_CMNINFO_RF_TYPE: -+ dm->rf_type = (u8)value; -+ break; -+ -+ case ODM_CMNINFO_WIFI_DIRECT: -+ dm->is_wifi_direct = (boolean)value; -+ break; -+ -+ case ODM_CMNINFO_WIFI_DISPLAY: -+ dm->is_wifi_display = (boolean)value; -+ break; -+ -+ case ODM_CMNINFO_LINK: -+ dm->is_linked = (boolean)value; -+ break; -+ -+ case ODM_CMNINFO_CMW500LINK: -+ dm->iot_table.is_linked_cmw500 = (boolean)value; -+ break; -+ -+ case ODM_CMNINFO_STATION_STATE: -+ dm->bsta_state = (boolean)value; -+ break; -+ -+ case ODM_CMNINFO_RSSI_MIN: -+ dm->rssi_min = (u8)value; -+ break; -+ -+ case ODM_CMNINFO_RSSI_MIN_BY_PATH: -+ dm->rssi_min_by_path = (u8)value; -+ break; -+ -+ case ODM_CMNINFO_DBG_COMP: -+ dm->debug_components = (u64)value; -+ break; -+ -+#ifdef ODM_CONFIG_BT_COEXIST -+ /* The following is for BT HS mode and BT coexist mechanism. */ -+ case ODM_CMNINFO_BT_ENABLED: -+ dm->bt_info_table.is_bt_enabled = (boolean)value; -+ break; -+ -+ case ODM_CMNINFO_BT_HS_CONNECT_PROCESS: -+ dm->bt_info_table.is_bt_connect_process = (boolean)value; -+ break; -+ -+ case ODM_CMNINFO_BT_HS_RSSI: -+ dm->bt_info_table.bt_hs_rssi = (u8)value; -+ break; -+ -+ case ODM_CMNINFO_BT_OPERATION: -+ dm->bt_info_table.is_bt_hs_operation = (boolean)value; -+ break; -+ -+ case ODM_CMNINFO_BT_LIMITED_DIG: -+ dm->bt_info_table.is_bt_limited_dig = (boolean)value; -+ break; -+#endif -+ -+ case ODM_CMNINFO_AP_TOTAL_NUM: -+ dm->ap_total_num = (u8)value; -+ break; -+ -+#ifdef CONFIG_PHYDM_DFS_MASTER -+ case ODM_CMNINFO_DFS_REGION_DOMAIN: -+ dm->dfs_region_domain = (u8)value; -+ break; -+#endif -+ -+ case ODM_CMNINFO_BT_CONTINUOUS_TURN: -+ dm->is_bt_continuous_turn = (boolean)value; -+ break; -+ default: -+ break; -+ } -+} -+ -+u32 phydm_cmn_info_query(struct dm_struct *dm, enum phydm_info_query info_type) -+{ -+ struct phydm_fa_struct *fa_t = &dm->false_alm_cnt; -+ struct phydm_dig_struct *dig_t = &dm->dm_dig_table; -+ struct ccx_info *ccx_info = &dm->dm_ccx_info; -+ -+ switch (info_type) { -+ /*@=== [FA Relative] ===========================================*/ -+ case PHYDM_INFO_FA_OFDM: -+ return fa_t->cnt_ofdm_fail; -+ -+ case PHYDM_INFO_FA_CCK: -+ return fa_t->cnt_cck_fail; -+ -+ case PHYDM_INFO_FA_TOTAL: -+ return fa_t->cnt_all; -+ -+ case PHYDM_INFO_CCA_OFDM: -+ return fa_t->cnt_ofdm_cca; -+ -+ case PHYDM_INFO_CCA_CCK: -+ return fa_t->cnt_cck_cca; -+ -+ case PHYDM_INFO_CCA_ALL: -+ return fa_t->cnt_cca_all; -+ -+ case PHYDM_INFO_CRC32_OK_VHT: -+ return fa_t->cnt_vht_crc32_ok; -+ -+ case PHYDM_INFO_CRC32_OK_HT: -+ return fa_t->cnt_ht_crc32_ok; -+ -+ case PHYDM_INFO_CRC32_OK_LEGACY: -+ return fa_t->cnt_ofdm_crc32_ok; -+ -+ case PHYDM_INFO_CRC32_OK_CCK: -+ return fa_t->cnt_cck_crc32_ok; -+ -+ case PHYDM_INFO_CRC32_ERROR_VHT: -+ return fa_t->cnt_vht_crc32_error; -+ -+ case PHYDM_INFO_CRC32_ERROR_HT: -+ return fa_t->cnt_ht_crc32_error; -+ -+ case PHYDM_INFO_CRC32_ERROR_LEGACY: -+ return fa_t->cnt_ofdm_crc32_error; -+ -+ case PHYDM_INFO_CRC32_ERROR_CCK: -+ return fa_t->cnt_cck_crc32_error; -+ -+ case PHYDM_INFO_EDCCA_FLAG: -+ return fa_t->edcca_flag; -+ -+ case PHYDM_INFO_OFDM_ENABLE: -+ return fa_t->ofdm_block_enable; -+ -+ case PHYDM_INFO_CCK_ENABLE: -+ return fa_t->cck_block_enable; -+ -+ case PHYDM_INFO_DBG_PORT_0: -+ return fa_t->dbg_port0; -+ -+ case PHYDM_INFO_CRC32_OK_HT_AGG: -+ return fa_t->cnt_ht_crc32_ok_agg; -+ -+ case PHYDM_INFO_CRC32_ERROR_HT_AGG: -+ return fa_t->cnt_ht_crc32_error_agg; -+ -+ /*@=== [DIG] ================================================*/ -+ -+ case PHYDM_INFO_CURR_IGI: -+ return dig_t->cur_ig_value; -+ -+ /*@=== [RSSI] ===============================================*/ -+ case PHYDM_INFO_RSSI_MIN: -+ return (u32)dm->rssi_min; -+ -+ case PHYDM_INFO_RSSI_MAX: -+ return (u32)dm->rssi_max; -+ -+ case PHYDM_INFO_CLM_RATIO: -+ return (u32)ccx_info->clm_ratio; -+ case PHYDM_INFO_NHM_RATIO: -+ return (u32)ccx_info->nhm_ratio; -+ default: -+ return 0xffffffff; -+ } -+} -+ -+#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) -+void odm_init_all_work_items(struct dm_struct *dm) -+{ -+ void *adapter = dm->adapter; -+#if USE_WORKITEM -+ -+#ifdef CONFIG_ADAPTIVE_SOML -+ odm_initialize_work_item(dm, -+ &dm->dm_soml_table.phydm_adaptive_soml_workitem, -+ (RT_WORKITEM_CALL_BACK)phydm_adaptive_soml_workitem_callback, -+ (void *)adapter, -+ "AdaptiveSOMLWorkitem"); -+#endif -+ -+#ifdef ODM_EVM_ENHANCE_ANTDIV -+ odm_initialize_work_item(dm, -+ &dm->phydm_evm_antdiv_workitem, -+ (RT_WORKITEM_CALL_BACK)phydm_evm_antdiv_workitem_callback, -+ (void *)adapter, -+ "EvmAntdivWorkitem"); -+#endif -+ -+#ifdef CONFIG_S0S1_SW_ANTENNA_DIVERSITY -+ odm_initialize_work_item(dm, -+ &dm->dm_swat_table.phydm_sw_antenna_switch_workitem, -+ (RT_WORKITEM_CALL_BACK)odm_sw_antdiv_workitem_callback, -+ (void *)adapter, -+ "AntennaSwitchWorkitem"); -+#endif -+#if (defined(CONFIG_HL_SMART_ANTENNA)) -+ odm_initialize_work_item(dm, -+ &dm->dm_sat_table.hl_smart_antenna_workitem, -+ (RT_WORKITEM_CALL_BACK)phydm_beam_switch_workitem_callback, -+ (void *)adapter, -+ "hl_smart_ant_workitem"); -+ -+ odm_initialize_work_item(dm, -+ &dm->dm_sat_table.hl_smart_antenna_decision_workitem, -+ (RT_WORKITEM_CALL_BACK)phydm_beam_decision_workitem_callback, -+ (void *)adapter, -+ "hl_smart_ant_decision_workitem"); -+#endif -+ -+ odm_initialize_work_item( -+ dm, -+ &dm->ra_rpt_workitem, -+ (RT_WORKITEM_CALL_BACK)halrf_update_init_rate_work_item_callback, -+ (void *)adapter, -+ "ra_rpt_workitem"); -+ -+#if (defined(CONFIG_5G_CG_SMART_ANT_DIVERSITY)) || (defined(CONFIG_2G_CG_SMART_ANT_DIVERSITY)) -+ odm_initialize_work_item( -+ dm, -+ &dm->fast_ant_training_workitem, -+ (RT_WORKITEM_CALL_BACK)odm_fast_ant_training_work_item_callback, -+ (void *)adapter, -+ "fast_ant_training_workitem"); -+#endif -+ -+#endif /*#if USE_WORKITEM*/ -+ -+#ifdef PHYDM_BEAMFORMING_SUPPORT -+ odm_initialize_work_item( -+ dm, -+ &dm->beamforming_info.txbf_info.txbf_enter_work_item, -+ (RT_WORKITEM_CALL_BACK)hal_com_txbf_enter_work_item_callback, -+ (void *)adapter, -+ "txbf_enter_work_item"); -+ -+ odm_initialize_work_item( -+ dm, -+ &dm->beamforming_info.txbf_info.txbf_leave_work_item, -+ (RT_WORKITEM_CALL_BACK)hal_com_txbf_leave_work_item_callback, -+ (void *)adapter, -+ "txbf_leave_work_item"); -+ -+ odm_initialize_work_item( -+ dm, -+ &dm->beamforming_info.txbf_info.txbf_fw_ndpa_work_item, -+ (RT_WORKITEM_CALL_BACK)hal_com_txbf_fw_ndpa_work_item_callback, -+ (void *)adapter, -+ "txbf_fw_ndpa_work_item"); -+ -+ odm_initialize_work_item( -+ dm, -+ &dm->beamforming_info.txbf_info.txbf_clk_work_item, -+ (RT_WORKITEM_CALL_BACK)hal_com_txbf_clk_work_item_callback, -+ (void *)adapter, -+ "txbf_clk_work_item"); -+ -+ odm_initialize_work_item( -+ dm, -+ &dm->beamforming_info.txbf_info.txbf_rate_work_item, -+ (RT_WORKITEM_CALL_BACK)hal_com_txbf_rate_work_item_callback, -+ (void *)adapter, -+ "txbf_rate_work_item"); -+ -+ odm_initialize_work_item( -+ dm, -+ &dm->beamforming_info.txbf_info.txbf_status_work_item, -+ (RT_WORKITEM_CALL_BACK)hal_com_txbf_status_work_item_callback, -+ (void *)adapter, -+ "txbf_status_work_item"); -+ -+ odm_initialize_work_item( -+ dm, -+ &dm->beamforming_info.txbf_info.txbf_reset_tx_path_work_item, -+ (RT_WORKITEM_CALL_BACK)hal_com_txbf_reset_tx_path_work_item_callback, -+ (void *)adapter, -+ "txbf_reset_tx_path_work_item"); -+ -+ odm_initialize_work_item( -+ dm, -+ &dm->beamforming_info.txbf_info.txbf_get_tx_rate_work_item, -+ (RT_WORKITEM_CALL_BACK)hal_com_txbf_get_tx_rate_work_item_callback, -+ (void *)adapter, -+ "txbf_get_tx_rate_work_item"); -+#endif -+ -+#if (PHYDM_LA_MODE_SUPPORT == 1) -+ odm_initialize_work_item( -+ dm, -+ &dm->adcsmp.adc_smp_work_item, -+ (RT_WORKITEM_CALL_BACK)adc_smp_work_item_callback, -+ (void *)adapter, -+ "adc_smp_work_item"); -+ -+ odm_initialize_work_item( -+ dm, -+ &dm->adcsmp.adc_smp_work_item_1, -+ (RT_WORKITEM_CALL_BACK)adc_smp_work_item_callback, -+ (void *)adapter, -+ "adc_smp_work_item_1"); -+#endif -+} -+ -+void odm_free_all_work_items(struct dm_struct *dm) -+{ -+#if USE_WORKITEM -+ -+#ifdef CONFIG_S0S1_SW_ANTENNA_DIVERSITY -+ odm_free_work_item(&dm->dm_swat_table.phydm_sw_antenna_switch_workitem); -+#endif -+ -+#ifdef CONFIG_ADAPTIVE_SOML -+ odm_free_work_item(&dm->dm_soml_table.phydm_adaptive_soml_workitem); -+#endif -+ -+#ifdef ODM_EVM_ENHANCE_ANTDIV -+ odm_free_work_item(&dm->phydm_evm_antdiv_workitem); -+#endif -+ -+#if (defined(CONFIG_HL_SMART_ANTENNA)) -+ odm_free_work_item(&dm->dm_sat_table.hl_smart_antenna_workitem); -+ odm_free_work_item(&dm->dm_sat_table.hl_smart_antenna_decision_workitem); -+#endif -+ -+#if (defined(CONFIG_5G_CG_SMART_ANT_DIVERSITY)) || (defined(CONFIG_2G_CG_SMART_ANT_DIVERSITY)) -+ odm_free_work_item(&dm->fast_ant_training_workitem); -+#endif -+ odm_free_work_item(&dm->ra_rpt_workitem); -+/*odm_free_work_item((&dm->sbdcnt_workitem));*/ -+#endif -+ -+#ifdef PHYDM_BEAMFORMING_SUPPORT -+ odm_free_work_item((&dm->beamforming_info.txbf_info.txbf_enter_work_item)); -+ odm_free_work_item((&dm->beamforming_info.txbf_info.txbf_leave_work_item)); -+ odm_free_work_item((&dm->beamforming_info.txbf_info.txbf_fw_ndpa_work_item)); -+ odm_free_work_item((&dm->beamforming_info.txbf_info.txbf_clk_work_item)); -+ odm_free_work_item((&dm->beamforming_info.txbf_info.txbf_rate_work_item)); -+ odm_free_work_item((&dm->beamforming_info.txbf_info.txbf_status_work_item)); -+ odm_free_work_item((&dm->beamforming_info.txbf_info.txbf_reset_tx_path_work_item)); -+ odm_free_work_item((&dm->beamforming_info.txbf_info.txbf_get_tx_rate_work_item)); -+#endif -+ -+#if (PHYDM_LA_MODE_SUPPORT == 1) -+ odm_free_work_item((&dm->adcsmp.adc_smp_work_item)); -+ odm_free_work_item((&dm->adcsmp.adc_smp_work_item_1)); -+#endif -+} -+#endif /*#if (DM_ODM_SUPPORT_TYPE == ODM_WIN)*/ -+ -+void odm_init_all_timers(struct dm_struct *dm) -+{ -+#if (defined(CONFIG_PHYDM_ANTENNA_DIVERSITY)) -+ odm_ant_div_timers(dm, INIT_ANTDIV_TIMMER); -+#endif -+#if (defined(PHYDM_TDMA_DIG_SUPPORT)) -+#ifdef IS_USE_NEW_TDMA -+ phydm_tdma_dig_timers(dm, INIT_TDMA_DIG_TIMMER); -+#endif -+#endif -+#ifdef CONFIG_ADAPTIVE_SOML -+ phydm_adaptive_soml_timers(dm, INIT_SOML_TIMMER); -+#endif -+#ifdef PHYDM_LNA_SAT_CHK_SUPPORT -+#ifdef PHYDM_LNA_SAT_CHK_TYPE1 -+ phydm_lna_sat_chk_timers(dm, INIT_LNA_SAT_CHK_TIMMER); -+#endif -+#endif -+ -+#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) -+ odm_initialize_timer(dm, &dm->sbdcnt_timer, -+ (void *)phydm_sbd_callback, NULL, "SbdTimer"); -+#ifdef PHYDM_BEAMFORMING_SUPPORT -+ odm_initialize_timer(dm, &dm->beamforming_info.txbf_info.txbf_fw_ndpa_timer, -+ (void *)hal_com_txbf_fw_ndpa_timer_callback, NULL, -+ "txbf_fw_ndpa_timer"); -+#endif -+#endif -+ -+#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE)) -+#ifdef PHYDM_BEAMFORMING_SUPPORT -+ odm_initialize_timer(dm, &dm->beamforming_info.beamforming_timer, -+ (void *)beamforming_sw_timer_callback, NULL, -+ "beamforming_timer"); -+#endif -+#endif -+} -+ -+void odm_cancel_all_timers(struct dm_struct *dm) -+{ -+#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) -+ /* @2012/01/12 MH Temp BSOD fix. We need to find NIC allocate mem fail reason in win7*/ -+ if (dm->adapter == NULL) -+ return; -+#endif -+ -+#if (defined(CONFIG_PHYDM_ANTENNA_DIVERSITY)) -+ odm_ant_div_timers(dm, CANCEL_ANTDIV_TIMMER); -+#endif -+#ifdef PHYDM_TDMA_DIG_SUPPORT -+#ifdef IS_USE_NEW_TDMA -+ phydm_tdma_dig_timers(dm, CANCEL_TDMA_DIG_TIMMER); -+#endif -+#endif -+#ifdef CONFIG_ADAPTIVE_SOML -+ phydm_adaptive_soml_timers(dm, CANCEL_SOML_TIMMER); -+#endif -+#ifdef PHYDM_LNA_SAT_CHK_SUPPORT -+#ifdef PHYDM_LNA_SAT_CHK_TYPE1 -+ phydm_lna_sat_chk_timers(dm, CANCEL_LNA_SAT_CHK_TIMMER); -+#endif -+#endif -+ -+#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) -+ odm_cancel_timer(dm, &dm->sbdcnt_timer); -+#ifdef PHYDM_BEAMFORMING_SUPPORT -+ odm_cancel_timer(dm, &dm->beamforming_info.txbf_info.txbf_fw_ndpa_timer); -+#endif -+#endif -+ -+#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE)) -+#ifdef PHYDM_BEAMFORMING_SUPPORT -+ odm_cancel_timer(dm, &dm->beamforming_info.beamforming_timer); -+#endif -+#endif -+} -+ -+void odm_release_all_timers(struct dm_struct *dm) -+{ -+#if (defined(CONFIG_PHYDM_ANTENNA_DIVERSITY)) -+ odm_ant_div_timers(dm, RELEASE_ANTDIV_TIMMER); -+#endif -+#ifdef PHYDM_TDMA_DIG_SUPPORT -+#ifdef IS_USE_NEW_TDMA -+ phydm_tdma_dig_timers(dm, RELEASE_TDMA_DIG_TIMMER); -+#endif -+#endif -+#ifdef CONFIG_ADAPTIVE_SOML -+ phydm_adaptive_soml_timers(dm, RELEASE_SOML_TIMMER); -+#endif -+#ifdef PHYDM_LNA_SAT_CHK_SUPPORT -+#ifdef PHYDM_LNA_SAT_CHK_TYPE1 -+ phydm_lna_sat_chk_timers(dm, RELEASE_LNA_SAT_CHK_TIMMER); -+#endif -+#endif -+ -+#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) -+ odm_release_timer(dm, &dm->sbdcnt_timer); -+#ifdef PHYDM_BEAMFORMING_SUPPORT -+ odm_release_timer(dm, &dm->beamforming_info.txbf_info.txbf_fw_ndpa_timer); -+#endif -+#endif -+ -+#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE)) -+#ifdef PHYDM_BEAMFORMING_SUPPORT -+ odm_release_timer(dm, &dm->beamforming_info.beamforming_timer); -+#endif -+#endif -+} -+ -+#if (DM_ODM_SUPPORT_TYPE == ODM_AP) -+void odm_init_all_threads( -+ struct dm_struct *dm) -+{ -+#ifdef TPT_THREAD -+ k_tpt_task_init(dm->priv); -+#endif -+} -+ -+void odm_stop_all_threads( -+ struct dm_struct *dm) -+{ -+#ifdef TPT_THREAD -+ k_tpt_task_stop(dm->priv); -+#endif -+} -+#endif -+ -+#if (DM_ODM_SUPPORT_TYPE == ODM_CE) -+/* @Justin: According to the current RRSI to adjust Response Frame TX power, -+ * 2012/11/05 -+ */ -+void odm_dtc(struct dm_struct *dm) -+{ -+#ifdef CONFIG_DM_RESP_TXAGC -+/* RSSI higher than this value, start to decade TX power */ -+#define DTC_BASE 35 -+ -+/* RSSI lower than this value, start to increase TX power */ -+#define DTC_DWN_BASE (DTC_BASE - 5) -+ -+ /* RSSI vs TX power step mapping: decade TX power */ -+ static const u8 dtc_table_down[] = { -+ DTC_BASE, -+ (DTC_BASE + 5), -+ (DTC_BASE + 10), -+ (DTC_BASE + 15), -+ (DTC_BASE + 20), -+ (DTC_BASE + 25)}; -+ -+ /* RSSI vs TX power step mapping: increase TX power */ -+ static const u8 dtc_table_up[] = { -+ DTC_DWN_BASE, -+ (DTC_DWN_BASE - 5), -+ (DTC_DWN_BASE - 10), -+ (DTC_DWN_BASE - 15), -+ (DTC_DWN_BASE - 15), -+ (DTC_DWN_BASE - 20), -+ (DTC_DWN_BASE - 20), -+ (DTC_DWN_BASE - 25), -+ (DTC_DWN_BASE - 25), -+ (DTC_DWN_BASE - 30), -+ (DTC_DWN_BASE - 35)}; -+ -+ u8 i; -+ u8 dtc_steps = 0; -+ u8 sign; -+ u8 resp_txagc = 0; -+ -+#if 0 -+ /* @As DIG is disabled, DTC is also disable */ -+ if (!(dm->support_ability & ODM_XXXXXX)) -+ return; -+#endif -+ -+ if (dm->rssi_min > DTC_BASE) { -+ /* need to decade the CTS TX power */ -+ sign = 1; -+ for (i = 0; i < ARRAY_SIZE(dtc_table_down); i++) { -+ if (dtc_table_down[i] >= dm->rssi_min || dtc_steps >= 6) -+ break; -+ else -+ dtc_steps++; -+ } -+ } -+#if 0 -+ else if (dm->rssi_min > DTC_DWN_BASE) { -+ /* needs to increase the CTS TX power */ -+ sign = 0; -+ dtc_steps = 1; -+ for (i = 0; i < ARRAY_SIZE(dtc_table_up); i++) { -+ if (dtc_table_up[i] <= dm->rssi_min || dtc_steps >= 10) -+ break; -+ else -+ dtc_steps++; -+ } -+ } -+#endif -+ else { -+ sign = 0; -+ dtc_steps = 0; -+ } -+ -+ resp_txagc = dtc_steps | (sign << 4); -+ resp_txagc = resp_txagc | (resp_txagc << 5); -+ odm_write_1byte(dm, 0x06d9, resp_txagc); -+ -+ PHYDM_DBG(dm, ODM_COMP_PWR_TRAIN, -+ "%s rssi_min:%u, set RESP_TXAGC to %s %u\n", __func__, -+ dm->rssi_min, sign ? "minus" : "plus", dtc_steps); -+#endif /* @CONFIG_RESP_TXAGC_ADJUST */ -+} -+ -+#endif /* @#if (DM_ODM_SUPPORT_TYPE == ODM_CE) */ -+ -+/*@<20170126, BB-Kevin>8188F D-CUT DC cancellation and 8821C*/ -+void phydm_dc_cancellation(struct dm_struct *dm) -+{ -+#ifdef PHYDM_DC_CANCELLATION -+ u32 offset_i_hex[PHYDM_MAX_RF_PATH] = {0}; -+ u32 offset_q_hex[PHYDM_MAX_RF_PATH] = {0}; -+ u32 reg_value32[PHYDM_MAX_RF_PATH] = {0}; -+ u8 path = RF_PATH_A; -+ u8 set_result; -+ -+ if (!(dm->support_ic_type & ODM_DC_CANCELLATION_SUPPORT)) -+ return; -+ if ((dm->support_ic_type & ODM_RTL8188F) && -+ dm->cut_version < ODM_CUT_D) -+ return; -+ if ((dm->support_ic_type & ODM_RTL8192F) && -+ dm->cut_version == ODM_CUT_A) -+ return; -+ -+ PHYDM_DBG(dm, ODM_COMP_API, "%s ======>\n", __func__); -+ -+ /*@DC_Estimation (only for 2x2 ic now) */ -+ -+ for (path = RF_PATH_A; path < PHYDM_MAX_RF_PATH; path++) { -+ if (path > RF_PATH_A && -+ dm->support_ic_type & (ODM_RTL8821C | ODM_RTL8188F | -+ ODM_RTL8710B | ODM_RTL8721D)) -+ break; -+ else if (path > RF_PATH_B && -+ dm->support_ic_type & (ODM_RTL8822B | ODM_RTL8192F)) -+ break; -+ if (phydm_stop_ic_trx(dm, PHYDM_SET) == PHYDM_SET_FAIL) { -+ PHYDM_DBG(dm, ODM_COMP_API, "STOP_TRX_FAIL\n"); -+ return; -+ } -+ odm_write_dig(dm, 0x7e); -+ /*@Disable LNA*/ -+ if (dm->support_ic_type & ODM_RTL8821C) -+ halrf_rf_lna_setting(dm, HALRF_LNA_DISABLE); -+ /*Turn off 3-wire*/ -+ phydm_stop_3_wire(dm, PHYDM_SET); -+ if (dm->support_ic_type & (ODM_RTL8188F | ODM_RTL8710B)) { -+ /*set debug port to 0x235*/ -+ if (!phydm_set_bb_dbg_port(dm, DBGPORT_PRI_1, 0x235)) { -+ PHYDM_DBG(dm, ODM_COMP_API, -+ "Set Debug port Fail\n"); -+ return; -+ } -+ } else if (dm->support_ic_type & ODM_RTL8721D) { -+ /*set debug port to 0x200*/ -+ if (!phydm_set_bb_dbg_port(dm, DBGPORT_PRI_2, 0x200)) { -+ PHYDM_DBG(dm, ODM_COMP_API, -+ "Set Debug port Fail\n"); -+ return; -+ } -+ } else if (dm->support_ic_type & ODM_RTL8821C) { -+ if (!phydm_set_bb_dbg_port(dm, DBGPORT_PRI_1, 0x200)) { -+ /*set debug port to 0x200*/ -+ PHYDM_DBG(dm, ODM_COMP_API, -+ "Set Debug port Fail\n"); -+ return; -+ } -+ phydm_bb_dbg_port_header_sel(dm, 0x0); -+ } else if (dm->support_ic_type & ODM_RTL8822B) { -+ if (path == RF_PATH_A && -+ !phydm_set_bb_dbg_port(dm, DBGPORT_PRI_1, 0x200)) { -+ /*set debug port to 0x200*/ -+ PHYDM_DBG(dm, ODM_COMP_API, -+ "Set Debug port Fail\n"); -+ return; -+ } -+ if (path == RF_PATH_B && -+ !phydm_set_bb_dbg_port(dm, DBGPORT_PRI_1, 0x202)) { -+ /*set debug port to 0x200*/ -+ PHYDM_DBG(dm, ODM_COMP_API, -+ "Set Debug port Fail\n"); -+ return; -+ } -+ phydm_bb_dbg_port_header_sel(dm, 0x0); -+ } else if (dm->support_ic_type & ODM_RTL8192F) { -+ if (path == RF_PATH_A && -+ !phydm_set_bb_dbg_port(dm, DBGPORT_PRI_1, 0x235)) { -+ /*set debug port to 0x235*/ -+ PHYDM_DBG(dm, ODM_COMP_API, -+ "Set Debug port Fail\n"); -+ return; -+ } -+ if (path == RF_PATH_B && -+ !phydm_set_bb_dbg_port(dm, DBGPORT_PRI_1, 0x23d)) { -+ /*set debug port to 0x23d*/ -+ PHYDM_DBG(dm, ODM_COMP_API, -+ "Set Debug port Fail\n"); -+ return; -+ } -+ } -+ -+ /*@disable CCK DCNF*/ -+ odm_set_bb_reg(dm, R_0xa78, MASKBYTE1, 0x0); -+ -+ PHYDM_DBG(dm, ODM_COMP_API, "DC cancellation Begin!!!\n"); -+ -+ phydm_stop_ck320(dm, true); /*stop ck320*/ -+ -+ /* the same debug port both for path-a and path-b*/ -+ reg_value32[path] = phydm_get_bb_dbg_port_val(dm); -+ -+ phydm_stop_ck320(dm, false); /*start ck320*/ -+ -+ phydm_release_bb_dbg_port(dm); -+ /* @Turn on 3-wire*/ -+ phydm_stop_3_wire(dm, PHYDM_REVERT); -+ /* @Enable LNA*/ -+ if (dm->support_ic_type & ODM_RTL8821C) -+ halrf_rf_lna_setting(dm, HALRF_LNA_ENABLE); -+ -+ odm_write_dig(dm, 0x20); -+ -+ set_result = phydm_stop_ic_trx(dm, PHYDM_REVERT); -+ -+ PHYDM_DBG(dm, ODM_COMP_API, "DC cancellation OK!!!\n"); -+ } -+ -+ /*@DC_Cancellation*/ -+ /*@DC compensation to CCK data path*/ -+ odm_set_bb_reg(dm, R_0xa9c, BIT(20), 0x1); -+ if (dm->support_ic_type & (ODM_RTL8188F | ODM_RTL8710B)) { -+ offset_i_hex[0] = (reg_value32[0] & 0xffc0000) >> 18; -+ offset_q_hex[0] = (reg_value32[0] & 0x3ff00) >> 8; -+ -+ /*@Before filling into registers, -+ *offset should be multiplexed (-1) -+ */ -+ offset_i_hex[0] = (offset_i_hex[0] >= 0x200) ? -+ (0x400 - offset_i_hex[0]) : -+ (0x1ff - offset_i_hex[0]); -+ offset_q_hex[0] = (offset_q_hex[0] >= 0x200) ? -+ (0x400 - offset_q_hex[0]) : -+ (0x1ff - offset_q_hex[0]); -+ -+ odm_set_bb_reg(dm, R_0x950, 0x1ff, offset_i_hex[0]); -+ odm_set_bb_reg(dm, R_0x950, 0x1ff0000, offset_q_hex[0]); -+ } else if (dm->support_ic_type & (ODM_RTL8821C | ODM_RTL8822B)) { -+ /* Path-a */ -+ offset_i_hex[0] = (reg_value32[0] & 0xffc00) >> 10; -+ offset_q_hex[0] = reg_value32[0] & 0x3ff; -+ -+ /*@Before filling into registers, -+ *offset should be multiplexed (-1) -+ */ -+ offset_i_hex[0] = 0x400 - offset_i_hex[0]; -+ offset_q_hex[0] = 0x400 - offset_q_hex[0]; -+ -+ odm_set_bb_reg(dm, R_0xc10, 0x3c000000, -+ (0x3c0 & offset_i_hex[0]) >> 6); -+ odm_set_bb_reg(dm, R_0xc10, 0xfc00, 0x3f & offset_i_hex[0]); -+ odm_set_bb_reg(dm, R_0xc14, 0x3c000000, -+ (0x3c0 & offset_q_hex[0]) >> 6); -+ odm_set_bb_reg(dm, R_0xc14, 0xfc00, 0x3f & offset_q_hex[0]); -+ -+ /* Path-b */ -+ if (dm->rf_type > RF_1T1R) { -+ offset_i_hex[1] = (reg_value32[1] & 0xffc00) >> 10; -+ offset_q_hex[1] = reg_value32[1] & 0x3ff; -+ -+ /*@Before filling into registers, -+ *offset should be multiplexed (-1) -+ */ -+ offset_i_hex[1] = 0x400 - offset_i_hex[1]; -+ offset_q_hex[1] = 0x400 - offset_q_hex[1]; -+ -+ odm_set_bb_reg(dm, R_0xe10, 0x3c000000, -+ (0x3c0 & offset_i_hex[1]) >> 6); -+ odm_set_bb_reg(dm, R_0xe10, 0xfc00, -+ 0x3f & offset_i_hex[1]); -+ odm_set_bb_reg(dm, R_0xe14, 0x3c000000, -+ (0x3c0 & offset_q_hex[1]) >> 6); -+ odm_set_bb_reg(dm, R_0xe14, 0xfc00, -+ 0x3f & offset_q_hex[1]); -+ } -+ } else if (dm->support_ic_type & (ODM_RTL8192F)) { -+ /* Path-a I:df4[27:18],Q:df4[17:8]*/ -+ offset_i_hex[0] = (reg_value32[0] & 0xffc0000) >> 18; -+ offset_q_hex[0] = (reg_value32[0] & 0x3ff00) >> 8; -+ -+ /*@Before filling into registers, -+ *offset should be multiplexed (-1) -+ */ -+ offset_i_hex[0] = (offset_i_hex[0] >= 0x200) ? -+ (0x400 - offset_i_hex[0]) : -+ (0xff - offset_i_hex[0]); -+ offset_q_hex[0] = (offset_q_hex[0] >= 0x200) ? -+ (0x400 - offset_q_hex[0]) : -+ (0xff - offset_q_hex[0]); -+ /*Path-a I:c10[7:0],Q:c10[15:8]*/ -+ odm_set_bb_reg(dm, R_0xc10, 0xff, offset_i_hex[0]); -+ odm_set_bb_reg(dm, R_0xc10, 0xff00, offset_q_hex[0]); -+ -+ /* Path-b */ -+ if (dm->rf_type > RF_1T1R) { -+ /* @I:df4[27:18],Q:df4[17:8]*/ -+ offset_i_hex[1] = (reg_value32[1] & 0xffc0000) >> 18; -+ offset_q_hex[1] = (reg_value32[1] & 0x3ff00) >> 8; -+ -+ /*@Before filling into registers, -+ *offset should be multiplexed (-1) -+ */ -+ offset_i_hex[1] = (offset_i_hex[1] >= 0x200) ? -+ (0x400 - offset_i_hex[1]) : -+ (0xff - offset_i_hex[1]); -+ offset_q_hex[1] = (offset_q_hex[1] >= 0x200) ? -+ (0x400 - offset_q_hex[1]) : -+ (0xff - offset_q_hex[1]); -+ /*Path-b I:c18[7:0],Q:c18[15:8]*/ -+ odm_set_bb_reg(dm, R_0xc18, 0xff, offset_i_hex[1]); -+ odm_set_bb_reg(dm, R_0xc18, 0xff00, offset_q_hex[1]); -+ } -+ } else if (dm->support_ic_type & (ODM_RTL8721D)) { -+ /*judy modified 20180517*/ -+ offset_i_hex[0] = (reg_value32[0] & 0xff800) >> 11; -+ offset_q_hex[0] = (reg_value32[0] & 0x3fe) >> 1; -+ -+ /*@Before filling into registers, -+ *offset should be multiplexed (-1) -+ */ -+ offset_i_hex[0] = 0x200 - offset_i_hex[0]; -+ offset_q_hex[0] = 0x200 - offset_q_hex[0]; -+ -+ odm_set_bb_reg(dm, R_0x950, 0x1ff, offset_i_hex[0]); -+ odm_set_bb_reg(dm, R_0x950, 0x1ff0000, offset_q_hex[0]); -+ } -+#endif -+} -+ -+void phydm_receiver_blocking(void *dm_void) -+{ -+#ifdef CONFIG_RECEIVER_BLOCKING -+ struct dm_struct *dm = (struct dm_struct *)dm_void; -+ u32 chnl = *dm->channel; -+ u8 bw = *dm->band_width; -+ u32 bb_regf0 = odm_get_bb_reg(dm, R_0xf0, 0xf000); -+ -+ if (!(dm->support_ic_type & ODM_RECEIVER_BLOCKING_SUPPORT) || -+ !(dm->support_ability & ODM_BB_ADAPTIVITY)) -+ return; -+ -+ if ((dm->support_ic_type & ODM_RTL8188E && bb_regf0 < 8) || -+ dm->support_ic_type & ODM_RTL8192E) { -+ /*@8188E_T version*/ -+ if (dm->consecutive_idlel_time <= 10 || *dm->mp_mode) -+ goto end; -+ -+ if (bw == CHANNEL_WIDTH_20 && chnl == 1) { -+ phydm_nbi_setting(dm, FUNC_ENABLE, chnl, 20, 2410, -+ PHYDM_DONT_CARE); -+ dm->is_rx_blocking_en = true; -+ } else if ((bw == CHANNEL_WIDTH_20) && (chnl == 13)) { -+ phydm_nbi_setting(dm, FUNC_ENABLE, chnl, 20, 2473, -+ PHYDM_DONT_CARE); -+ dm->is_rx_blocking_en = true; -+ } else if (dm->is_rx_blocking_en && chnl != 1 && chnl != 13) { -+ phydm_nbi_enable(dm, FUNC_DISABLE); -+ odm_set_bb_reg(dm, R_0xc40, 0x1f000000, 0x1f); -+ dm->is_rx_blocking_en = false; -+ } -+ return; -+ } else if ((dm->support_ic_type & ODM_RTL8188E && bb_regf0 >= 8)) { -+ /*@8188E_S version*/ -+ if (dm->consecutive_idlel_time <= 10 || *dm->mp_mode) -+ goto end; -+ -+ if (bw == CHANNEL_WIDTH_20 && chnl == 13) { -+ phydm_nbi_setting(dm, FUNC_ENABLE, chnl, 20, 2473, -+ PHYDM_DONT_CARE); -+ dm->is_rx_blocking_en = true; -+ } else if (dm->is_rx_blocking_en && chnl != 13) { -+ phydm_nbi_enable(dm, FUNC_DISABLE); -+ odm_set_bb_reg(dm, R_0xc40, 0x1f000000, 0x1f); -+ dm->is_rx_blocking_en = false; -+ } -+ return; -+ } -+ -+end: -+ if (dm->is_rx_blocking_en) { -+ phydm_nbi_enable(dm, FUNC_DISABLE); -+ odm_set_bb_reg(dm, R_0xc40, 0x1f000000, 0x1f); -+ dm->is_rx_blocking_en = false; -+ } -+#endif -+} -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm.h -new file mode 100644 -index 000000000..820be2fa8 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm.h -@@ -0,0 +1,1356 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * The full GNU General Public License is included in this distribution in the -+ * file called LICENSE. -+ * -+ * Contact Information: -+ * wlanfae -+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, -+ * Hsinchu 300, Taiwan. -+ * -+ * Larry Finger -+ * -+ *****************************************************************************/ -+ -+#ifndef __HALDMOUTSRC_H__ -+#define __HALDMOUTSRC_H__ -+ -+/*@============================================================*/ -+/*@include files*/ -+/*@============================================================*/ -+/*PHYDM header*/ -+#include "phydm_pre_define.h" -+#include "phydm_features.h" -+#include "phydm_dig.h" -+#ifdef CONFIG_PATH_DIVERSITY -+#include "phydm_pathdiv.h" -+#endif -+#ifdef CONFIG_PHYDM_ANTENNA_DIVERSITY -+#include "phydm_antdiv.h" -+#endif -+ -+#include "phydm_soml.h" -+ -+#ifdef CONFIG_SMART_ANTENNA -+#include "phydm_smt_ant.h" -+#endif -+#ifdef CONFIG_ANT_DETECTION -+#include "phydm_antdect.h" -+#endif -+#include "phydm_rainfo.h" -+#ifdef CONFIG_DYNAMIC_TX_TWR -+#include "phydm_dynamictxpower.h" -+#endif -+#include "phydm_cfotracking.h" -+#include "phydm_adaptivity.h" -+#include "phydm_dfs.h" -+#include "phydm_ccx.h" -+#include "txbf/phydm_hal_txbf_api.h" -+#if (PHYDM_LA_MODE_SUPPORT == 1) -+#include "phydm_adc_sampling.h" -+#endif -+#ifdef CONFIG_PSD_TOOL -+#include "phydm_psd.h" -+#endif -+#ifdef PHYDM_PRIMARY_CCA -+#include "phydm_primary_cca.h" -+#endif -+#include "phydm_cck_pd.h" -+#include "phydm_rssi_monitor.h" -+#ifdef PHYDM_AUTO_DEGBUG -+#include "phydm_auto_dbg.h" -+#endif -+#include "phydm_math_lib.h" -+#include "phydm_noisemonitor.h" -+#include "phydm_api.h" -+#ifdef PHYDM_POWER_TRAINING_SUPPORT -+#include "phydm_pow_train.h" -+#endif -+#ifdef PHYDM_LNA_SAT_CHK_SUPPORT -+#include "phydm_lna_sat.h" -+#endif -+#ifdef PHYDM_PMAC_TX_SETTING_SUPPORT -+#include "phydm_pmac_tx_setting.h" -+#endif -+#ifdef PHYDM_MP_SUPPORT -+#include "phydm_mp.h" -+#endif -+#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE)) -+ #include "phydm_beamforming.h" -+#endif -+ -+#include "phydm_regtable.h" -+ -+/*@HALRF header*/ -+#include "halrf/halrf_iqk.h" -+#include "halrf/halrf_dpk.h" -+#include "halrf/halrf.h" -+#include "halrf/halrf_powertracking.h" -+#if (DM_ODM_SUPPORT_TYPE & (ODM_AP)) -+ #include "halrf/halphyrf_ap.h" -+#elif(DM_ODM_SUPPORT_TYPE & (ODM_CE)) -+ #include "halrf/halphyrf_ce.h" -+#elif (DM_ODM_SUPPORT_TYPE & (ODM_WIN)) -+ #include "halrf/halphyrf_win.h" -+#elif(DM_ODM_SUPPORT_TYPE & (ODM_IOT)) -+ #include "halrf/halphyrf_iot.h" -+#endif -+ -+extern const u16 phy_rate_table[28]; -+ -+/*@============================================================*/ -+/*@Definition */ -+/*@============================================================*/ -+ -+/* Traffic load decision */ -+#define TRAFFIC_NO_TP 0 -+#define TRAFFIC_ULTRA_LOW 1 -+#define TRAFFIC_LOW 2 -+#define TRAFFIC_MID 3 -+#define TRAFFIC_HIGH 4 -+ -+#define NONE 0 -+ -+#if defined(DM_ODM_CE_MAC80211) -+#define MAX_2(x, y) \ -+ __max2(typeof(x), typeof(y), \ -+ x, y) -+#define __max2(t1, t2, x, y) ({ \ -+ t1 m80211_max1 = (x); \ -+ t2 m80211_max2 = (y); \ -+ m80211_max1 > m80211_max2 ? m80211_max1 : m80211_max2; }) -+ -+#define MIN_2(x, y) \ -+ __min2(typeof(x), typeof(y), \ -+ x, y) -+#define __min2(t1, t2, x, y) ({ \ -+ t1 m80211_min1 = (x); \ -+ t2 m80211_min2 = (y); \ -+ m80211_min1 < m80211_min2 ? m80211_min1 : m80211_min2; }) -+ -+#define DIFF_2(x, y) \ -+ __diff2(typeof(x), typeof(y), \ -+ x, y) -+#define __diff2(t1, t2, x, y) ({ \ -+ t1 __d1 = (x); \ -+ t2 __d2 = (y); \ -+ (__d1 >= __d2) ? (__d1 - __d2) : (__d2 - __d1); }) -+#else -+#define MAX_2(_x_, _y_) (((_x_) > (_y_)) ? (_x_) : (_y_)) -+#define MIN_2(_x_, _y_) (((_x_) < (_y_)) ? (_x_) : (_y_)) -+#define DIFF_2(_x_, _y_) ((_x_ >= _y_) ? (_x_ - _y_) : (_y_ - _x_)) -+#endif -+ -+#define IS_GREATER(_x_, _y_) (((_x_) >= (_y_)) ? true : false) -+#define IS_LESS(_x_, _y_) (((_x_) < (_y_)) ? true : false) -+ -+#if defined(DM_ODM_CE_MAC80211) -+#define BYTE_DUPLICATE_2_DWORD(B0) ({ \ -+ u32 __b_dup = (B0);\ -+ (((__b_dup) << 24) | ((__b_dup) << 16) | ((__b_dup) << 8) | (__b_dup));\ -+ }) -+#else -+#define BYTE_DUPLICATE_2_DWORD(B0) \ -+ (((B0) << 24) | ((B0) << 16) | ((B0) << 8) | (B0)) -+#endif -+#define BYTE_2_DWORD(B3, B2, B1, B0) \ -+ (((B3) << 24) | ((B2) << 16) | ((B1) << 8) | (B0)) -+#define BIT_2_BYTE(B3, B2, B1, B0) \ -+ (((B3) << 3) | ((B2) << 2) | ((B1) << 1) | (B0)) -+ -+/*@For cmn sta info*/ -+#if defined(DM_ODM_CE_MAC80211) -+#define is_sta_active(sta) ({ \ -+ struct cmn_sta_info *__sta = (sta); \ -+ ((__sta) && (__sta->dm_ctrl & STA_DM_CTRL_ACTIVE)); \ -+ }) -+ -+#define IS_FUNC_EN(name) ({ \ -+ u8 *__is_func_name = (name); \ -+ (__is_func_name) && (*__is_func_name); \ -+ }) -+#else -+#define is_sta_active(sta) ((sta) && (sta->dm_ctrl & STA_DM_CTRL_ACTIVE)) -+ -+#define IS_FUNC_EN(name) ((name) && (*name)) -+#endif -+ -+#if (DM_ODM_SUPPORT_TYPE == ODM_AP) -+ #define PHYDM_WATCH_DOG_PERIOD 1 /*second*/ -+#else -+ #define PHYDM_WATCH_DOG_PERIOD 2 /*second*/ -+#endif -+ -+#define PHY_HIST_SIZE 12 -+ -+/*@============================================================*/ -+/*structure and define*/ -+/*@============================================================*/ -+ -+#define dm_type_by_fw 0 -+#define dm_type_by_driver 1 -+ -+#ifdef BB_RAM_SUPPORT -+ -+struct phydm_bb_ram_per_sta { -+ /* @Reg0x1E84 for RAM I/O*/ -+ boolean hw_igi_en; -+ boolean tx_pwr_offset0_en; -+ boolean tx_pwr_offset1_en; -+ /* @ macid from 0 to 63, above 63 => mapping to 63*/ -+ u8 macid_addr; -+ /* @hw_igi value for paths after packet Tx in a period of time*/ -+ u8 hw_igi; -+ /* @tx_pwr_offset0 offset for Tx power index*/ -+ s8 tx_pwr_offset0; -+ s8 tx_pwr_offset1; -+ -+}; -+ -+struct phydm_bb_ram_ctrl { -+ /*@ For 98F/14B/22C/12F, each TxAGC step will be 0.25dB*/ -+ struct phydm_bb_ram_per_sta pram_sta_ctrl[ODM_ASSOCIATE_ENTRY_NUM]; -+ /*------------ For table2 do not set power offset by macid --------*/ -+ /* For type == 2'b10, 0x1e70[22:16] = tx_pwr_offset_reg0, 0x1e70[23] = enable */ -+ boolean tx_pwr_offset_reg0_en; -+ u8 tx_pwr_offset_reg0; -+ /* For type == 2'b11, 0x1e70[30:24] = tx_pwr_offset_reg1, 0x1e70[31] = enable */ -+ boolean tx_pwr_offset_reg1_en; -+ u8 tx_pwr_offset_reg1; -+}; -+ -+#endif -+ -+struct phydm_phystatus_statistic { -+ /*@[CCK]*/ -+ u32 rssi_cck_sum; -+ u32 rssi_cck_cnt; -+ /*@[OFDM]*/ -+ u32 rssi_ofdm_sum; -+ u32 rssi_ofdm_cnt; -+ u32 evm_ofdm_sum; -+ u32 snr_ofdm_sum; -+ u16 evm_ofdm_hist[PHY_HIST_SIZE]; -+ u16 snr_ofdm_hist[PHY_HIST_SIZE]; -+ /*@[1SS]*/ -+ u32 rssi_1ss_cnt; -+ u32 rssi_1ss_sum; -+ u32 evm_1ss_sum; -+ u32 snr_1ss_sum; -+ u16 evm_1ss_hist[PHY_HIST_SIZE]; -+ u16 snr_1ss_hist[PHY_HIST_SIZE]; -+ /*@[2SS]*/ -+ #if (defined(PHYDM_COMPILE_ABOVE_2SS)) -+ u32 rssi_2ss_cnt; -+ u32 rssi_2ss_sum[2]; -+ u32 evm_2ss_sum[2]; -+ u32 snr_2ss_sum[2]; -+ u16 evm_2ss_hist[2][PHY_HIST_SIZE]; -+ u16 snr_2ss_hist[2][PHY_HIST_SIZE]; -+ #endif -+ /*@[3SS]*/ -+ #if (defined(PHYDM_COMPILE_ABOVE_3SS)) -+ u32 rssi_3ss_cnt; -+ u32 rssi_3ss_sum[3]; -+ u32 evm_3ss_sum[3]; -+ u32 snr_3ss_sum[3]; -+ u16 evm_3ss_hist[3][PHY_HIST_SIZE]; -+ u16 snr_3ss_hist[3][PHY_HIST_SIZE]; -+ #endif -+ /*@[4SS]*/ -+ #if (defined(PHYDM_COMPILE_ABOVE_4SS)) -+ u32 rssi_4ss_cnt; -+ u32 rssi_4ss_sum[4]; -+ u32 evm_4ss_sum[4]; -+ u32 snr_4ss_sum[4]; -+ u16 evm_4ss_hist[4][PHY_HIST_SIZE]; -+ u16 snr_4ss_hist[4][PHY_HIST_SIZE]; -+ #endif -+}; -+ -+struct phydm_phystatus_avg { -+ /*@[CCK]*/ -+ u8 rssi_cck_avg; -+ /*@[OFDM]*/ -+ u8 rssi_ofdm_avg; -+ u8 evm_ofdm_avg; -+ u8 snr_ofdm_avg; -+ /*@[1SS]*/ -+ u8 rssi_1ss_avg; -+ u8 evm_1ss_avg; -+ u8 snr_1ss_avg; -+ /*@[2SS]*/ -+ #if (defined(PHYDM_COMPILE_ABOVE_2SS)) -+ u8 rssi_2ss_avg[2]; -+ u8 evm_2ss_avg[2]; -+ u8 snr_2ss_avg[2]; -+ #endif -+ /*@[3SS]*/ -+ #if (defined(PHYDM_COMPILE_ABOVE_3SS)) -+ u8 rssi_3ss_avg[3]; -+ u8 evm_3ss_avg[3]; -+ u8 snr_3ss_avg[3]; -+ #endif -+ /*@[4SS]*/ -+ #if (defined(PHYDM_COMPILE_ABOVE_4SS)) -+ u8 rssi_4ss_avg[4]; -+ u8 evm_4ss_avg[4]; -+ u8 snr_4ss_avg[4]; -+ #endif -+}; -+ -+struct odm_phy_dbg_info { -+ /*@ODM Write,debug info*/ -+ u32 num_qry_phy_status_cck; -+ u32 num_qry_phy_status_ofdm; -+#if (ODM_PHY_STATUS_NEW_TYPE_SUPPORT == 1) || (defined(PHYSTS_3RD_TYPE_SUPPORT)) -+ u32 num_qry_mu_pkt; -+ u32 num_qry_bf_pkt; -+ u16 num_mu_vht_pkt[VHT_RATE_NUM]; -+ boolean is_ldpc_pkt; -+ boolean is_stbc_pkt; -+ u8 num_of_ppdu[4]; -+ u8 gid_num[4]; -+#endif -+ u32 condi_num; /*@condition number U(18,4)*/ -+ u8 condi_num_cdf[CN_CNT_MAX]; -+ u8 num_qry_beacon_pkt; -+ u8 beacon_cnt_in_period; /*@beacon cnt within watchdog period*/ -+ u8 beacon_phy_rate; -+ u8 show_phy_sts_all_pkt; /*@Show phy status witch not match BSSID*/ -+ u16 show_phy_sts_max_cnt; /*@show number of phy-status row data per PHYDM watchdog*/ -+ u16 show_phy_sts_cnt; -+ u16 num_qry_legacy_pkt[LEGACY_RATE_NUM]; -+ u16 num_qry_ht_pkt[HT_RATE_NUM]; -+ u16 num_qry_pkt_sc_20m[LOW_BW_RATE_NUM]; /*@20M SC*/ -+ boolean ht_pkt_not_zero; -+ boolean low_bw_20_occur; -+ #if ODM_IC_11AC_SERIES_SUPPORT || defined(PHYDM_IC_JGR3_SERIES_SUPPORT) -+ u16 num_qry_vht_pkt[VHT_RATE_NUM]; -+ u16 num_qry_pkt_sc_40m[LOW_BW_RATE_NUM]; /*@40M SC*/ -+ boolean vht_pkt_not_zero; -+ boolean low_bw_40_occur; -+ #endif -+ u16 snr_hist_th[PHY_HIST_SIZE - 1]; -+ u16 evm_hist_th[PHY_HIST_SIZE - 1]; -+ #ifdef PHYDM_IC_JGR3_SERIES_SUPPORT -+ s16 cfo_tail[4]; /* per-path's cfo_tail */ -+ #endif -+ struct phydm_phystatus_statistic physts_statistic_info; -+ struct phydm_phystatus_avg phystatus_statistic_avg; -+}; -+ -+enum odm_cmninfo { -+ /*@Fixed value*/ -+ /*@-----------HOOK BEFORE REG INIT-----------*/ -+ ODM_CMNINFO_PLATFORM = 0, -+ ODM_CMNINFO_ABILITY, -+ ODM_CMNINFO_INTERFACE, -+ ODM_CMNINFO_MP_TEST_CHIP, -+ ODM_CMNINFO_IC_TYPE, -+ ODM_CMNINFO_CUT_VER, -+ ODM_CMNINFO_FAB_VER, -+ ODM_CMNINFO_FW_VER, -+ ODM_CMNINFO_FW_SUB_VER, -+ ODM_CMNINFO_RF_TYPE, -+ ODM_CMNINFO_RFE_TYPE, -+ ODM_CMNINFO_DPK_EN, -+ ODM_CMNINFO_BOARD_TYPE, -+ ODM_CMNINFO_PACKAGE_TYPE, -+ ODM_CMNINFO_EXT_LNA, -+ ODM_CMNINFO_5G_EXT_LNA, -+ ODM_CMNINFO_EXT_PA, -+ ODM_CMNINFO_5G_EXT_PA, -+ ODM_CMNINFO_GPA, -+ ODM_CMNINFO_APA, -+ ODM_CMNINFO_GLNA, -+ ODM_CMNINFO_ALNA, -+ ODM_CMNINFO_TDMA, -+ ODM_CMNINFO_EXT_TRSW, -+ ODM_CMNINFO_EXT_LNA_GAIN, -+ ODM_CMNINFO_PATCH_ID, -+ ODM_CMNINFO_BINHCT_TEST, -+ ODM_CMNINFO_BWIFI_TEST, -+ ODM_CMNINFO_SMART_CONCURRENT, -+ ODM_CMNINFO_CONFIG_BB_RF, -+ ODM_CMNINFO_IQKPAOFF, -+ ODM_CMNINFO_HUBUSBMODE, -+ ODM_CMNINFO_FWDWRSVDPAGEINPROGRESS, -+ ODM_CMNINFO_TX_TP, -+ ODM_CMNINFO_RX_TP, -+ ODM_CMNINFO_SOUNDING_SEQ, -+ ODM_CMNINFO_REGRFKFREEENABLE, -+ ODM_CMNINFO_RFKFREEENABLE, -+ ODM_CMNINFO_NORMAL_RX_PATH_CHANGE, -+ ODM_CMNINFO_EFUSE0X3D8, -+ ODM_CMNINFO_EFUSE0X3D7, -+ ODM_CMNINFO_SOFT_AP_SPECIAL_SETTING, -+ ODM_CMNINFO_X_CAP_SETTING, -+ ODM_CMNINFO_ADVANCE_OTA, -+ ODM_CMNINFO_HP_HWID, -+ /*@-----------HOOK BEFORE REG INIT-----------*/ -+ -+ /*@Dynamic value:*/ -+ -+ /*@--------- POINTER REFERENCE-----------*/ -+ ODM_CMNINFO_TX_UNI, -+ ODM_CMNINFO_RX_UNI, -+ ODM_CMNINFO_BAND, -+ ODM_CMNINFO_SEC_CHNL_OFFSET, -+ ODM_CMNINFO_SEC_MODE, -+ ODM_CMNINFO_BW, -+ ODM_CMNINFO_CHNL, -+ ODM_CMNINFO_FORCED_RATE, -+ ODM_CMNINFO_ANT_DIV, -+ ODM_CMNINFO_PATH_DIV, -+ ODM_CMNINFO_ADAPTIVE_SOML, -+ ODM_CMNINFO_ADAPTIVITY, -+ ODM_CMNINFO_SCAN, -+ ODM_CMNINFO_POWER_SAVING, -+ ODM_CMNINFO_ONE_PATH_CCA, -+ ODM_CMNINFO_DRV_STOP, -+ ODM_CMNINFO_PNP_IN, -+ ODM_CMNINFO_INIT_ON, -+ ODM_CMNINFO_ANT_TEST, -+ ODM_CMNINFO_NET_CLOSED, -+ ODM_CMNINFO_P2P_LINK, -+ ODM_CMNINFO_FCS_MODE, -+ ODM_CMNINFO_IS1ANTENNA, -+ ODM_CMNINFO_RFDEFAULTPATH, -+ ODM_CMNINFO_DFS_MASTER_ENABLE, -+ ODM_CMNINFO_FORCE_TX_ANT_BY_TXDESC, -+ ODM_CMNINFO_SET_S0S1_DEFAULT_ANTENNA, -+ ODM_CMNINFO_SOFT_AP_MODE, -+ ODM_CMNINFO_MP_MODE, -+ ODM_CMNINFO_INTERRUPT_MASK, -+ ODM_CMNINFO_BB_OPERATION_MODE, -+ ODM_CMNINFO_BF_ANTDIV_DECISION, -+ /*@--------- POINTER REFERENCE-----------*/ -+ -+ /*@------------CALL BY VALUE-------------*/ -+ ODM_CMNINFO_WIFI_DIRECT, -+ ODM_CMNINFO_WIFI_DISPLAY, -+ ODM_CMNINFO_LINK_IN_PROGRESS, -+ ODM_CMNINFO_LINK, -+ ODM_CMNINFO_CMW500LINK, -+ ODM_CMNINFO_STATION_STATE, -+ ODM_CMNINFO_RSSI_MIN, -+ ODM_CMNINFO_RSSI_MIN_BY_PATH, -+ ODM_CMNINFO_DBG_COMP, -+ ODM_CMNINFO_RA_THRESHOLD_HIGH, /*to be removed*/ -+ ODM_CMNINFO_RA_THRESHOLD_LOW, /*to be removed*/ -+ ODM_CMNINFO_RF_ANTENNA_TYPE, -+ ODM_CMNINFO_WITH_EXT_ANTENNA_SWITCH, -+ ODM_CMNINFO_BE_FIX_TX_ANT, -+ ODM_CMNINFO_BT_ENABLED, -+ ODM_CMNINFO_BT_HS_CONNECT_PROCESS, -+ ODM_CMNINFO_BT_HS_RSSI, -+ ODM_CMNINFO_BT_OPERATION, -+ ODM_CMNINFO_BT_LIMITED_DIG, -+ ODM_CMNINFO_AP_TOTAL_NUM, -+ ODM_CMNINFO_POWER_TRAINING, -+ ODM_CMNINFO_DFS_REGION_DOMAIN, -+ ODM_CMNINFO_BT_CONTINUOUS_TURN, -+ /*@------------CALL BY VALUE-------------*/ -+ -+ /*@Dynamic ptr array hook itms.*/ -+ ODM_CMNINFO_STA_STATUS, -+ ODM_CMNINFO_MAX, -+ -+}; -+ -+enum phydm_rfe_bb_source_sel { -+ PAPE_2G = 0, -+ PAPE_5G = 1, -+ LNA0N_2G = 2, -+ LNAON_5G = 3, -+ TRSW = 4, -+ TRSW_B = 5, -+ GNT_BT = 6, -+ ZERO = 7, -+ ANTSEL_0 = 8, -+ ANTSEL_1 = 9, -+ ANTSEL_2 = 0xa, -+ ANTSEL_3 = 0xb, -+ ANTSEL_4 = 0xc, -+ ANTSEL_5 = 0xd, -+ ANTSEL_6 = 0xe, -+ ANTSEL_7 = 0xf -+}; -+ -+enum phydm_info_query { -+ PHYDM_INFO_FA_OFDM, -+ PHYDM_INFO_FA_CCK, -+ PHYDM_INFO_FA_TOTAL, -+ PHYDM_INFO_CCA_OFDM, -+ PHYDM_INFO_CCA_CCK, -+ PHYDM_INFO_CCA_ALL, -+ PHYDM_INFO_CRC32_OK_VHT, -+ PHYDM_INFO_CRC32_OK_HT, -+ PHYDM_INFO_CRC32_OK_LEGACY, -+ PHYDM_INFO_CRC32_OK_CCK, -+ PHYDM_INFO_CRC32_ERROR_VHT, -+ PHYDM_INFO_CRC32_ERROR_HT, -+ PHYDM_INFO_CRC32_ERROR_LEGACY, -+ PHYDM_INFO_CRC32_ERROR_CCK, -+ PHYDM_INFO_EDCCA_FLAG, -+ PHYDM_INFO_OFDM_ENABLE, -+ PHYDM_INFO_CCK_ENABLE, -+ PHYDM_INFO_CRC32_OK_HT_AGG, -+ PHYDM_INFO_CRC32_ERROR_HT_AGG, -+ PHYDM_INFO_DBG_PORT_0, -+ PHYDM_INFO_CURR_IGI, -+ PHYDM_INFO_RSSI_MIN, -+ PHYDM_INFO_RSSI_MAX, -+ PHYDM_INFO_CLM_RATIO, -+ PHYDM_INFO_NHM_RATIO, -+}; -+ -+enum phydm_api { -+ PHYDM_API_NBI = 1, -+ PHYDM_API_CSI_MASK = 2, -+}; -+ -+enum phydm_func_idx { /*@F_XXX = PHYDM XXX function*/ -+ -+ F00_DIG = 0, -+ F01_RA_MASK = 1, -+ F02_DYN_TXPWR = 2, -+ F03_FA_CNT = 3, -+ F04_RSSI_MNTR = 4, -+ F05_CCK_PD = 5, -+ F06_ANT_DIV = 6, -+ F07_SMT_ANT = 7, -+ F08_PWR_TRAIN = 8, -+ F09_RA = 9, -+ F10_PATH_DIV = 10, -+ F11_DFS = 11, -+ F12_DYN_ARFR = 12, -+ F13_ADPTVTY = 13, -+ F14_CFO_TRK = 14, -+ F15_ENV_MNTR = 15, -+ F16_PRI_CCA = 16, -+ F17_ADPTV_SOML = 17, -+ F18_LNA_SAT_CHK = 18, -+}; -+ -+/*@=[PHYDM supportability]==========================================*/ -+enum odm_ability { -+ ODM_BB_DIG = BIT(F00_DIG), -+ ODM_BB_RA_MASK = BIT(F01_RA_MASK), -+ ODM_BB_DYNAMIC_TXPWR = BIT(F02_DYN_TXPWR), -+ ODM_BB_FA_CNT = BIT(F03_FA_CNT), -+ ODM_BB_RSSI_MONITOR = BIT(F04_RSSI_MNTR), -+ ODM_BB_CCK_PD = BIT(F05_CCK_PD), -+ ODM_BB_ANT_DIV = BIT(F06_ANT_DIV), -+ ODM_BB_SMT_ANT = BIT(F07_SMT_ANT), -+ ODM_BB_PWR_TRAIN = BIT(F08_PWR_TRAIN), -+ ODM_BB_RATE_ADAPTIVE = BIT(F09_RA), -+ ODM_BB_PATH_DIV = BIT(F10_PATH_DIV), -+ ODM_BB_DFS = BIT(F11_DFS), -+ ODM_BB_DYNAMIC_ARFR = BIT(F12_DYN_ARFR), -+ ODM_BB_ADAPTIVITY = BIT(F13_ADPTVTY), -+ ODM_BB_CFO_TRACKING = BIT(F14_CFO_TRK), -+ ODM_BB_ENV_MONITOR = BIT(F15_ENV_MNTR), -+ ODM_BB_PRIMARY_CCA = BIT(F16_PRI_CCA), -+ ODM_BB_ADAPTIVE_SOML = BIT(F17_ADPTV_SOML), -+ ODM_BB_LNA_SAT_CHK = BIT(F18_LNA_SAT_CHK), -+}; -+ -+/*@=[PHYDM Debug Component]=====================================*/ -+enum phydm_dbg_comp { -+ /*@BB Driver Functions*/ -+ DBG_DIG = BIT(F00_DIG), -+ DBG_RA_MASK = BIT(F01_RA_MASK), -+ DBG_DYN_TXPWR = BIT(F02_DYN_TXPWR), -+ DBG_FA_CNT = BIT(F03_FA_CNT), -+ DBG_RSSI_MNTR = BIT(F04_RSSI_MNTR), -+ DBG_CCKPD = BIT(F05_CCK_PD), -+ DBG_ANT_DIV = BIT(F06_ANT_DIV), -+ DBG_SMT_ANT = BIT(F07_SMT_ANT), -+ DBG_PWR_TRAIN = BIT(F08_PWR_TRAIN), -+ DBG_RA = BIT(F09_RA), -+ DBG_PATH_DIV = BIT(F10_PATH_DIV), -+ DBG_DFS = BIT(F11_DFS), -+ DBG_DYN_ARFR = BIT(F12_DYN_ARFR), -+ DBG_ADPTVTY = BIT(F13_ADPTVTY), -+ DBG_CFO_TRK = BIT(F14_CFO_TRK), -+ DBG_ENV_MNTR = BIT(F15_ENV_MNTR), -+ DBG_PRI_CCA = BIT(F16_PRI_CCA), -+ DBG_ADPTV_SOML = BIT(F17_ADPTV_SOML), -+ DBG_LNA_SAT_CHK = BIT(F18_LNA_SAT_CHK), -+ /*BIT(19)*/ -+ /*Neet to re-arrange*/ -+ DBG_PHY_STATUS = BIT(20), -+ DBG_TMP = BIT(21), -+ DBG_FW_TRACE = BIT(22), -+ DBG_TXBF = BIT(23), -+ DBG_COMMON_FLOW = BIT(24), -+ DBG_COMP_MCC = BIT(25), -+ /*BIT(26)*/ -+ DBG_DM_SUMMARY = BIT(27), -+ ODM_PHY_CONFIG = BIT(28), -+ ODM_COMP_INIT = BIT(29), -+ DBG_CMN = BIT(30),/*@common*/ -+ ODM_COMP_API = BIT(31) -+}; -+ -+/*@=========================================================*/ -+ -+/*@ODM_CMNINFO_ONE_PATH_CCA*/ -+enum odm_cca_path { -+ ODM_CCA_2R = 0, -+ ODM_CCA_1R_A = 1, -+ ODM_CCA_1R_B = 2, -+}; -+ -+enum phy_reg_pg_type { -+ PHY_REG_PG_RELATIVE_VALUE = 0, -+ PHY_REG_PG_EXACT_VALUE = 1 -+}; -+ -+enum phydm_offload_ability { -+ PHYDM_PHY_PARAM_OFFLOAD = BIT(0), -+ PHYDM_RF_IQK_OFFLOAD = BIT(1), -+}; -+ -+struct phydm_pause_lv { -+ s8 lv_dig; -+ s8 lv_cckpd; -+ s8 lv_antdiv; -+ s8 lv_adapt; -+ s8 lv_adsl; -+}; -+ -+struct phydm_func_poiner { -+ void (*pause_phydm_handler)(void *dm_void, u32 *val_buf, u8 val_len); -+}; -+ -+struct pkt_process_info { -+ u8 phystatus_smp_mode_en; /*@send phystatus every sampling time*/ -+ u8 pre_ppdu_cnt; -+ u8 lna_idx; -+ u8 vga_idx; -+}; -+ -+#ifdef ODM_CONFIG_BT_COEXIST -+struct phydm_bt_info { -+ boolean is_bt_enabled; /*@BT is enabled*/ -+ boolean is_bt_connect_process; /*@BT HS is under connection progress.*/ -+ u8 bt_hs_rssi; /*@BT HS mode wifi rssi value.*/ -+ boolean is_bt_hs_operation; /*@BT HS mode is under progress*/ -+ boolean is_bt_limited_dig; /*@BT is busy.*/ -+}; -+#endif -+ -+struct phydm_iot_center { -+ boolean is_linked_cmw500; -+ u8 win_patch_id; /*@Customer ID*/ -+ u32 phydm_patch_id; -+ -+}; -+ -+#if (RTL8822B_SUPPORT == 1) -+struct drp_rtl8822b_struct { -+ enum bb_path path_judge; -+ u16 path_a_cck_fa; -+ u16 path_b_cck_fa; -+}; -+#endif -+ -+#ifdef CONFIG_MCC_DM -+#define MCC_DM_REG_NUM 32 -+struct _phydm_mcc_dm_ { -+ u8 mcc_pre_status; -+ u8 mcc_reg_id[MCC_DM_REG_NUM]; -+ u16 mcc_dm_reg[MCC_DM_REG_NUM]; -+ u8 mcc_dm_val[MCC_DM_REG_NUM][2]; -+ /*mcc DIG*/ -+ u8 mcc_rssi[2]; -+ /*u8 mcc_igi[2];*/ -+ -+ /* need to be config by driver*/ -+ u8 mcc_status; -+ u8 sta_macid[2][NUM_STA]; -+ u16 mcc_rf_channel[2]; -+ -+}; -+#endif -+ -+ -+#if (DM_ODM_SUPPORT_TYPE & ODM_WIN) -+ #if (RT_PLATFORM != PLATFORM_LINUX) -+ typedef -+ #endif -+ -+struct dm_struct { -+#else/*for AP, CE Team*/ -+struct dm_struct { -+#endif -+ /*@Add for different team use temporarily*/ -+ void *adapter; /*@For CE/NIC team*/ -+ struct rtl8192cd_priv *priv; /*@For AP team*/ -+ boolean odm_ready; -+ enum phy_reg_pg_type phy_reg_pg_value_type; -+ u8 phy_reg_pg_version; -+ u64 support_ability; /*@PHYDM function Supportability*/ -+ u64 pause_ability; /*@PHYDM function pause Supportability*/ -+ u64 debug_components; -+ u8 cmn_dbg_msg_period; -+ u8 cmn_dbg_msg_cnt; -+ u32 fw_debug_components; -+ u32 num_qry_phy_status_all; /*@CCK + OFDM*/ -+ u32 last_num_qry_phy_status_all; -+ u32 rx_pwdb_ave; -+ boolean is_init_hw_info_by_rfe; -+ -+ /*@------ ODM HANDLE, DRIVER NEEDS NOT TO HOOK------*/ -+ boolean is_cck_high_power; -+ u8 rf_path_rx_enable; -+ /*@------ ODM HANDLE, DRIVER NEEDS NOT TO HOOK------*/ -+ -+ /* @COMMON INFORMATION */ -+ -+ /*@Init value*/ -+ /*@-----------HOOK BEFORE REG INIT-----------*/ -+ -+ u8 support_platform; /*@PHYDM Platform info WIN/AP/CE = 1/2/3 */ -+ u8 normal_rx_path; -+ boolean brxagcswitch; /* @for rx AGC table switch in Microsoft case */ -+ u8 support_interface; /*@PHYDM PCIE/USB/SDIO = 1/2/3*/ -+ u32 support_ic_type; /*@PHYDM supported IC*/ -+ u8 ic_ip_series; /*N/AC/JGR3*/ -+ enum phydm_phy_sts_type ic_phy_sts_type; /*@Type1/type2/type3*/ -+ u8 cut_version; /*@cut version TestChip/A-cut/B-cut... = 0/1/2/3/...*/ -+ u8 fab_version; /*@Fab version TSMC/UMC = 0/1*/ -+ u8 fw_version; -+ u8 fw_sub_version; -+ u8 rf_type; /*@RF type 4T4R/3T3R/2T2R/1T2R/1T1R/...*/ -+ u8 rfe_type; -+ u8 board_type; -+ u8 package_type; -+ u16 type_glna; -+ u16 type_gpa; -+ u16 type_alna; -+ u16 type_apa; -+ u8 ext_lna; /*@with 2G external LNA NO/Yes = 0/1*/ -+ u8 ext_lna_5g; /*@with 5G external LNA NO/Yes = 0/1*/ -+ u8 ext_pa; /*@with 2G external PNA NO/Yes = 0/1*/ -+ u8 ext_pa_5g; /*@with 5G external PNA NO/Yes = 0/1*/ -+ u8 efuse0x3d7; /*@with Efuse number*/ -+ u8 efuse0x3d8; -+ u8 ext_trsw; /*@with external TRSW NO/Yes = 0/1*/ -+ u8 ext_lna_gain; /*@gain of external lna*/ -+ boolean is_in_hct_test; -+ u8 wifi_test; -+ boolean is_dual_mac_smart_concurrent; -+ u32 bk_support_ability; /*SD4 only*/ -+ u8 with_extenal_ant_switch; -+ /*@cck agc relative*/ -+ boolean cck_new_agc; -+ s8 cck_lna_gain_table[8]; -+ /*@-------------------------------------*/ -+ u32 phydm_sys_up_time; -+ u8 num_rf_path; /*@ex: 8821C=1, 8192E=2, 8814B=4*/ -+ u32 soft_ap_special_setting; -+ s8 s8_dummy; -+ u8 u8_dummy; -+ u16 u16_dummy; -+ u32 u32_dummy; -+ u8 rfe_hwsetting_band; -+ u8 p_advance_ota; -+ boolean hp_hw_id; -+ boolean BOOLEAN_temp; -+ boolean is_dfs_band; -+ u8 is_rx_blocking_en; -+ u16 fw_offload_ability; -+/*@-----------HOOK BEFORE REG INIT-----------*/ -+/*@===========================================================*/ -+/*@====[ CALL BY Reference ]=========================================*/ -+/*@===========================================================*/ -+ -+ u64 *num_tx_bytes_unicast; /*@TX Unicast byte cnt*/ -+ u64 *num_rx_bytes_unicast; /*@RX Unicast byte cnt*/ -+ u8 *band_type; /*@2.4G/5G = 0/1*/ -+ u8 *sec_ch_offset; /*@Secondary channel offset don't_care/below/above = 0/1/2*/ -+ u8 *security; /*@security mode Open/WEP/AES/TKIP = 0/1/2/3*/ -+ u8 *band_width; /*@20M/40M/80M = 0/1/2*/ -+ u8 *channel; /*@central CH number*/ -+ boolean *is_scan_in_process; -+ boolean *is_power_saving; -+ boolean *is_tdma; -+ u8 *one_path_cca; /*@CCA path 2-path/path-A/path-B = 0/1/2; using enum odm_cca_path.*/ -+ u8 *antenna_test; -+ boolean *is_net_closed; -+ boolean *is_fcs_mode_enable; -+ /*@--------- For 8723B IQK-------------------------------------*/ -+ boolean *is_1_antenna; -+ u8 *rf_default_path; /* @0:S1, 1:S0 */ -+ /*@-----------------------------------------------------------*/ -+ -+ u16 *forced_data_rate; -+ u8 *enable_antdiv; -+ u8 *enable_pathdiv; -+ u8 *en_adap_soml; -+ u8 *enable_adaptivity; -+ u8 *hub_usb_mode; /*@1:USB2.0, 2:USB3.0*/ -+ boolean *is_fw_dw_rsvd_page_in_progress; -+ u32 *current_tx_tp; -+ u32 *current_rx_tp; -+ u8 *sounding_seq; -+ u32 *soft_ap_mode; -+ u8 *mp_mode; -+ u32 *interrupt_mask; -+ u8 *bb_op_mode; -+/*@===========================================================*/ -+/*@====[ CALL BY VALUE ]===========================================*/ -+/*@===========================================================*/ -+ -+ u8 disable_phydm_watchdog; -+ boolean is_link_in_process; -+ boolean is_wifi_direct; -+ boolean is_wifi_display; -+ boolean is_linked; -+ boolean bsta_state; -+ u8 rssi_min; -+ u8 rssi_min_macid; -+ u8 pre_rssi_min; -+ u8 rssi_max; -+ u8 rssi_max_macid; -+ u8 rssi_min_by_path; -+ boolean is_one_entry_only; -+ u32 one_entry_macid; -+ u32 one_entry_tp; -+ u32 pre_one_entry_tp; -+ u8 pre_number_linked_client; -+ u8 number_linked_client; -+ u8 pre_number_active_client; -+ u8 number_active_client; -+ boolean is_disable_phy_api; -+ u8 rssi_a; -+ u8 rssi_b; -+ u8 rssi_c; -+ u8 rssi_d; -+ s8 rxsc_80; -+ s8 rxsc_40; -+ s8 rxsc_20; -+ s8 rxsc_l; -+ u64 rssi_trsw; -+ u64 rssi_trsw_h; -+ u64 rssi_trsw_l; -+ u64 rssi_trsw_iso; -+ u8 tx_ant_status; -+ u8 rx_ant_status; -+ u8 cck_lna_idx; -+ u8 cck_vga_idx; -+ u8 curr_station_id; -+ u8 ofdm_agc_idx[4]; -+ u8 rx_rate; -+ u8 rate_ss; -+ u8 tx_rate; -+ u8 linked_interval; -+ u8 pre_channel; -+ u32 txagc_offset_value_a; -+ boolean is_txagc_offset_positive_a; -+ u32 txagc_offset_value_b; -+ boolean is_txagc_offset_positive_b; -+ u8 ap_total_num; -+ /*@[traffic]*/ -+ u8 traffic_load; -+ u8 pre_traffic_load; -+ u32 tx_tp; /*@Mbps*/ -+ u32 rx_tp; /*@Mbps*/ -+ u32 total_tp; /*@Mbps*/ -+ u8 txrx_state_all; /*@0:tx, 1:rx, 2:bi-dir*/ -+ u64 cur_tx_ok_cnt; -+ u64 cur_rx_ok_cnt; -+ u64 last_tx_ok_cnt; -+ u64 last_rx_ok_cnt; -+ u16 consecutive_idlel_time; /*@unit: second*/ -+ /*@---------------------------*/ -+ boolean is_bb_swing_offset_positive_a; -+ boolean is_bb_swing_offset_positive_b; -+ -+ /*@[DIG]*/ -+ boolean MPDIG_2G; /*off MPDIG*/ -+ u8 times_2g; /*@for MP DIG*/ -+ u8 force_igi; /*@for debug*/ -+ -+ /*@[TDMA-DIG]*/ -+ u8 tdma_dig_timer_ms; -+ u8 tdma_dig_state_number; -+ u8 tdma_dig_low_upper_bond; -+ u8 force_tdma_low_igi; -+ u8 force_tdma_high_igi; -+ u8 fix_expire_to_zero; -+ boolean original_dig_restore; -+ /*@---------------------------*/ -+ -+ /*@[AntDiv]*/ -+ u8 ant_div_type; -+ u8 antdiv_rssi; -+ u8 fat_comb_a; -+ u8 fat_comb_b; -+ u8 antdiv_intvl; -+ u8 ant_type; -+ u8 ant_type2; -+ u8 pre_ant_type; -+ u8 pre_ant_type2; -+ u8 antdiv_period; -+ u8 evm_antdiv_period; -+ u8 antdiv_select; -+ u8 antdiv_train_num; /*@training time for each antenna in EVM method*/ -+ u8 stop_antdiv_rssi_th; -+ u16 stop_antdiv_tp_diff_th; -+ u16 stop_antdiv_tp_th; -+ u8 antdiv_tp_period; -+ u16 tp_active_th; -+ u8 tp_active_occur; -+ u8 path_select; -+ u8 antdiv_evm_en; -+ u8 bdc_holdstate; -+ u8 antdiv_counter; -+ /*@---------------------------*/ -+ -+ u8 ndpa_period; -+ boolean h2c_rarpt_connect; -+ boolean cck_agc_report_type; /*@1:4bit LNA, 0:3bit LNA */ -+ u8 print_agc; -+ u8 la_mode; -+ /*@---8821C Antenna and RF Set BTG/WLG/WLA Select---------------*/ -+ u8 current_rf_set_8821c; -+ u8 default_rf_set_8821c; -+ u8 current_ant_num_8821c; -+ u8 default_ant_num_8821c; -+ u8 rfe_type_expand; -+ /*@-----------------------------------------------------------*/ -+ /*@---For Adaptivtiy---------------------------------------------*/ -+ s8 TH_L2H_default; -+ s8 th_edcca_hl_diff_default; -+ s8 th_l2h_ini; -+ s8 th_edcca_hl_diff; -+ boolean carrier_sense_enable; -+ /*@-----------------------------------------------------------*/ -+ -+ u8 pre_dbg_priority; -+ u8 nbi_set_result; -+ u8 c2h_cmd_start; -+ u8 fw_debug_trace[60]; -+ u8 pre_c2h_seq; -+ boolean fw_buff_is_enpty; -+ u32 data_frame_num; -+ -+ /*@--- for noise detection ---------------------------------------*/ -+ boolean is_noisy_state; -+ boolean noisy_decision; /*@b_noisy*/ -+ boolean pre_b_noisy; -+ u32 noisy_decision_smooth; -+ /*@-----------------------------------------------------------*/ -+ -+ /*@--- for MCC ant weighting ------------------------------------*/ -+ boolean is_stop_dym_ant_weighting; -+ /*@-----------------------------------------------------------*/ -+ -+ boolean is_disable_dym_ecs; -+ boolean is_disable_dym_ant_weighting; -+ struct cmn_sta_info *phydm_sta_info[ODM_ASSOCIATE_ENTRY_NUM]; -+ u8 phydm_macid_table[ODM_ASSOCIATE_ENTRY_NUM];/*@sta_idx = phydm_macid_table[HW_macid]*/ -+ -+#if (RATE_ADAPTIVE_SUPPORT == 1) -+ u16 currmin_rpt_time; -+ struct _phydm_txstatistic_ hw_stats; -+ struct _odm_ra_info_ ra_info[ODM_ASSOCIATE_ENTRY_NUM]; -+/*Use mac_id as array index. STA mac_id=0*/ -+/*VWiFi Client mac_id={1, ODM_ASSOCIATE_ENTRY_NUM-1} //YJ,add,120119*/ -+#endif -+ /*@2012/02/14 MH Add to share 88E ra with other SW team*/ -+ /*We need to colelct all support abilit to a proper area.*/ -+ boolean ra_support88e; -+ boolean *is_driver_stopped; -+ boolean *is_driver_is_going_to_pnp_set_power_sleep; -+ boolean *pinit_adpt_in_progress; -+ boolean is_user_assign_level; -+ u8 RSSI_BT; /*@come from BT*/ -+ -+ /*@---PSD Relative ---------------------------------------------*/ -+ boolean is_psd_in_process; -+ boolean is_psd_active; -+ /*@-----------------------------------------------------------*/ -+ -+ boolean bsomlenabled; /* @D-SoML control */ -+ boolean bhtstfdisabled; /* @dynamic HTSTF gain control*/ -+ u32 n_iqk_cnt; -+ u32 n_iqk_ok_cnt; -+ u32 n_iqk_fail_cnt; -+ -+#if (DM_ODM_SUPPORT_TYPE & ODM_AP) -+ boolean config_bbrf; -+#endif -+ boolean is_disable_power_training; -+ boolean is_bt_continuous_turn; -+ u8 enhance_pwr_th[3]; -+ u8 set_pwr_th[3]; -+ /*@----------Dyn Tx Pwr ---------------------------------------*/ -+#ifdef BB_RAM_SUPPORT -+ struct phydm_bb_ram_ctrl p_bb_ram_ctrl; -+#endif -+ u8 dynamic_tx_high_power_lvl; -+ void (*fill_desc_dyntxpwr)(void *dm, u8 *desc, u8 dyn_tx_power); -+ u8 last_dtp_lvl; -+ u8 min_power_index; -+ u32 tx_agc_ofdm_18_6; -+ /*-------------------------------------------------------------*/ -+ u8 rx_pkt_type; -+ -+#ifdef CONFIG_PHYDM_DFS_MASTER -+ u8 dfs_region_domain; -+ u8 *dfs_master_enabled; -+ /*@---phydm_radar_detect_with_dbg_parm start --------------------*/ -+ u8 radar_detect_dbg_parm_en; -+ u32 radar_detect_reg_918; -+ u32 radar_detect_reg_91c; -+ u32 radar_detect_reg_920; -+ u32 radar_detect_reg_924; -+ u32 radar_detect_reg_f54; -+ u32 radar_detect_reg_f58; -+ u32 radar_detect_reg_f5c; -+ u32 radar_detect_reg_f70; -+ u32 radar_detect_reg_f74; -+/*@-----------------------------------------------------------*/ -+#endif -+ -+/*@=== PHYDM Timer ========================================== (start)*/ -+ -+ struct phydm_timer_list mpt_dig_timer; -+ struct phydm_timer_list fast_ant_training_timer; -+#ifdef ODM_EVM_ENHANCE_ANTDIV -+ struct phydm_timer_list evm_fast_ant_training_timer; -+#endif -+#ifdef PHYDM_TDMA_DIG_SUPPORT -+ struct phydm_timer_list tdma_dig_timer; -+#endif -+ struct phydm_timer_list sbdcnt_timer; -+ -+/*@=== PHYDM Workitem ======================================= (start)*/ -+ -+#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) -+#if USE_WORKITEM -+ RT_WORK_ITEM fast_ant_training_workitem; -+ RT_WORK_ITEM ra_rpt_workitem; -+ RT_WORK_ITEM sbdcnt_workitem; -+ RT_WORK_ITEM phydm_evm_antdiv_workitem; -+#endif -+#endif -+ -+/*@=== PHYDM Structure ======================================== (start)*/ -+ struct phydm_func_poiner phydm_func_handler; -+ struct phydm_iot_center iot_table; -+ -+#ifdef ODM_CONFIG_BT_COEXIST -+ struct phydm_bt_info bt_info_table; -+#endif -+ -+ struct pkt_process_info pkt_proc_struct; -+ struct phydm_adaptivity_struct adaptivity; -+ struct _DFS_STATISTICS dfs; -+ struct odm_noise_monitor noise_level; -+ struct odm_phy_dbg_info phy_dbg_info; -+ -+#ifdef CONFIG_ADAPTIVE_SOML -+ struct adaptive_soml dm_soml_table; -+#endif -+ -+#if (defined(CONFIG_PHYDM_ANTENNA_DIVERSITY)) -+ #if (DM_ODM_SUPPORT_TYPE & (ODM_AP)) -+ struct _BF_DIV_COEX_ dm_bdc_table; -+ #endif -+ -+ #if (defined(CONFIG_HL_SMART_ANTENNA)) -+ struct smt_ant_honbo dm_sat_table; -+ #endif -+#endif -+ -+#if (defined(CONFIG_SMART_ANTENNA)) -+ struct smt_ant smtant_table; -+#endif -+ -+ struct _hal_rf_ rf_table; /*@for HALRF function*/ -+ struct dm_rf_calibration_struct rf_calibrate_info; -+ struct dm_iqk_info IQK_info; -+ struct dm_dpk_info dpk_info; -+ -+#ifdef CONFIG_PHYDM_ANTENNA_DIVERSITY -+ struct phydm_fat_struct dm_fat_table; -+ struct sw_antenna_switch dm_swat_table; -+#endif -+ struct phydm_dig_struct dm_dig_table; -+#ifdef PHYDM_LNA_SAT_CHK_SUPPORT -+ struct phydm_lna_sat_t dm_lna_sat_info; -+#endif -+ -+#ifdef CONFIG_MCC_DM -+ struct _phydm_mcc_dm_ mcc_dm; -+#endif -+ -+#ifdef PHYDM_SUPPORT_CCKPD -+ struct phydm_cckpd_struct dm_cckpd_table; -+#endif -+ -+#ifdef PHYDM_PRIMARY_CCA -+ struct phydm_pricca_struct dm_pri_cca; -+#endif -+ -+ struct ra_table dm_ra_table; -+ struct phydm_fa_struct false_alm_cnt; -+#ifdef PHYDM_TDMA_DIG_SUPPORT -+ struct phydm_fa_acc_struct false_alm_cnt_acc; -+#ifdef IS_USE_NEW_TDMA -+ struct phydm_fa_acc_struct false_alm_cnt_acc_low; -+#endif -+#endif -+ struct phydm_cfo_track_struct dm_cfo_track; -+ struct ccx_info dm_ccx_info; -+ -+ struct odm_power_trim_data power_trim_data; -+#if (RTL8822B_SUPPORT == 1) -+ struct drp_rtl8822b_struct phydm_rtl8822b; -+#endif -+ -+#ifdef CONFIG_PSD_TOOL -+ struct psd_info dm_psd_table; -+#endif -+ -+#if (PHYDM_LA_MODE_SUPPORT == 1) -+ struct rt_adcsmp adcsmp; -+#endif -+ -+#if (defined(CONFIG_PATH_DIVERSITY)) -+ struct _ODM_PATH_DIVERSITY_ dm_path_div; -+#endif -+ -+#if (defined(CONFIG_ANT_DETECTION)) -+ struct _ANT_DETECTED_INFO ant_detected_info; -+#endif -+ -+#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE)) -+#ifdef PHYDM_BEAMFORMING_SUPPORT -+ struct _RT_BEAMFORMING_INFO beamforming_info; -+#endif -+#endif -+#ifdef PHYDM_AUTO_DEGBUG -+ struct phydm_auto_dbg_struct auto_dbg_table; -+#endif -+ -+ struct phydm_pause_lv pause_lv_table; -+ struct phydm_api_stuc api_table; -+#ifdef PHYDM_POWER_TRAINING_SUPPORT -+ struct phydm_pow_train_stuc pow_train_table; -+#endif -+ -+#ifdef PHYDM_PMAC_TX_SETTING_SUPPORT -+ struct phydm_pmac_tx dm_pmac_tx_table; -+#endif -+ -+#ifdef PHYDM_MP_SUPPORT -+ struct phydm_mp dm_mp_table; -+#endif -+/*@==========================================================*/ -+ -+#if (DM_ODM_SUPPORT_TYPE & ODM_WIN) -+ -+#if (RT_PLATFORM != PLATFORM_LINUX) -+} dm_struct; /*@DM_Dynamic_Mechanism_Structure*/ -+#else -+}; -+#endif -+ -+#else /*@for AP,CE Team*/ -+}; -+#endif -+ -+enum phydm_adv_ota { -+ PHYDM_PATHB_1RCCA = BIT(0), -+ PHYDM_HP_OTA_SETTING_A = BIT(1), -+ PHYDM_HP_OTA_SETTING_B = BIT(2), -+ PHYDM_ASUS_OTA_SETTING = BIT(3), -+ PHYDM_ASUS_OTA_SETTING_CCK_PATH = BIT(4), -+ PHYDM_HP_OTA_SETTING_CCK_PATH = BIT(5), -+ PHYDM_LENOVO_OTA_SETTING_NBI_CSI = BIT(6), -+ -+}; -+ -+enum phydm_bb_op_mode { -+ PHYDM_PERFORMANCE_MODE = 0, /*Service one device*/ -+ PHYDM_BALANCE_MODE = 1, /*@Service more than one device*/ -+}; -+ -+enum phydm_structure_type { -+ PHYDM_FALSEALMCNT, -+ PHYDM_CFOTRACK, -+ PHYDM_ADAPTIVITY, -+ PHYDM_DFS, -+ PHYDM_ROMINFO, -+ -+}; -+ -+enum odm_bb_config_type { -+ CONFIG_BB_PHY_REG, -+ CONFIG_BB_AGC_TAB, -+ CONFIG_BB_AGC_TAB_2G, -+ CONFIG_BB_AGC_TAB_5G, -+ CONFIG_BB_PHY_REG_PG, -+ CONFIG_BB_PHY_REG_MP, -+ CONFIG_BB_AGC_TAB_DIFF, -+ CONFIG_BB_RF_CAL_INIT, -+}; -+ -+enum odm_rf_config_type { -+ CONFIG_RF_RADIO, -+ CONFIG_RF_TXPWR_LMT, -+ CONFIG_RF_SYN_RADIO, -+}; -+ -+enum odm_fw_config_type { -+ CONFIG_FW_NIC, -+ CONFIG_FW_NIC_2, -+ CONFIG_FW_AP, -+ CONFIG_FW_AP_2, -+ CONFIG_FW_MP, -+ CONFIG_FW_WOWLAN, -+ CONFIG_FW_WOWLAN_2, -+ CONFIG_FW_AP_WOWLAN, -+ CONFIG_FW_BT, -+}; -+ -+/*status code*/ -+#if (DM_ODM_SUPPORT_TYPE != ODM_WIN) -+enum rt_status { -+ RT_STATUS_SUCCESS, -+ RT_STATUS_FAILURE, -+ RT_STATUS_PENDING, -+ RT_STATUS_RESOURCE, -+ RT_STATUS_INVALID_CONTEXT, -+ RT_STATUS_INVALID_PARAMETER, -+ RT_STATUS_NOT_SUPPORT, -+ RT_STATUS_OS_API_FAILED, -+}; -+#endif /*@end of enum rt_status definition*/ -+ -+void -+phydm_watchdog_lps(struct dm_struct *dm); -+ -+void -+phydm_watchdog_lps_32k(struct dm_struct *dm); -+ -+void -+phydm_txcurrentcalibration(struct dm_struct *dm); -+ -+void -+phydm_dm_early_init(struct dm_struct *dm); -+ -+void -+odm_dm_init(struct dm_struct *dm); -+ -+void -+odm_dm_reset(struct dm_struct *dm); -+ -+void -+phydm_fwoffload_ability_init(struct dm_struct *dm, -+ enum phydm_offload_ability offload_ability); -+ -+void -+phydm_fwoffload_ability_clear(struct dm_struct *dm, -+ enum phydm_offload_ability offload_ability); -+ -+void -+phydm_supportability_en(void *dm_void, char input[][16], u32 *_used, -+ char *output, u32 *_out_len); -+ -+void -+phydm_pause_dm_watchdog(void *dm_void, enum phydm_pause_type pause_type); -+ -+void -+phydm_watchdog(struct dm_struct *dm); -+ -+void -+phydm_watchdog_mp(struct dm_struct *dm); -+ -+u8 -+phydm_pause_func(void *dm_void, enum phydm_func_idx pause_func, -+ enum phydm_pause_type pause_type, -+ enum phydm_pause_level pause_lv, u8 val_lehgth, u32 *val_buf); -+ -+void -+phydm_pause_func_console(void *dm_void, char input[][16], u32 *_used, -+ char *output, u32 *_out_len); -+ -+void -+odm_cmn_info_init(struct dm_struct *dm, enum odm_cmninfo cmn_info, u64 value); -+ -+void -+odm_cmn_info_hook(struct dm_struct *dm, enum odm_cmninfo cmn_info, void *value); -+ -+void -+odm_cmn_info_update(struct dm_struct *dm, u32 cmn_info, u64 value); -+ -+u32 -+phydm_cmn_info_query(struct dm_struct *dm, enum phydm_info_query info_type); -+ -+void -+odm_init_all_timers(struct dm_struct *dm); -+ -+void -+odm_cancel_all_timers(struct dm_struct *dm); -+ -+void -+odm_release_all_timers(struct dm_struct *dm); -+ -+void * -+phydm_get_structure(struct dm_struct *dm, u8 structure_type); -+ -+void -+phydm_dc_cancellation(struct dm_struct *dm); -+ -+void -+phydm_receiver_blocking(void *dm_void); -+ -+#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) -+void -+odm_init_all_work_items( -+ struct dm_struct *dm -+); -+void -+odm_free_all_work_items( -+ struct dm_struct *dm -+); -+#endif /*@#if (DM_ODM_SUPPORT_TYPE == ODM_WIN)*/ -+ -+#if (DM_ODM_SUPPORT_TYPE == ODM_CE) -+void -+odm_dtc(struct dm_struct *dm); -+#endif -+ -+#if (DM_ODM_SUPPORT_TYPE == ODM_AP) -+void -+odm_init_all_threads( -+ struct dm_struct *dm -+); -+ -+void -+odm_stop_all_threads( -+ struct dm_struct *dm -+); -+#endif -+ -+#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm.mk linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm.mk -new file mode 100644 -index 000000000..a05df647d ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm.mk -@@ -0,0 +1,226 @@ -+EXTRA_CFLAGS += -I$(src)/hal/phydm -+ -+_PHYDM_FILES := hal/phydm/phydm_debug.o \ -+ hal/phydm/phydm_antdiv.o\ -+ hal/phydm/phydm_soml.o\ -+ hal/phydm/phydm_smt_ant.o\ -+ hal/phydm/phydm_antdect.o\ -+ hal/phydm/phydm_interface.o\ -+ hal/phydm/phydm_phystatus.o\ -+ hal/phydm/phydm_hwconfig.o\ -+ hal/phydm/phydm.o\ -+ hal/phydm/phydm_dig.o\ -+ hal/phydm/phydm_pathdiv.o\ -+ hal/phydm/phydm_rainfo.o\ -+ hal/phydm/phydm_dynamictxpower.o\ -+ hal/phydm/phydm_adaptivity.o\ -+ hal/phydm/phydm_cfotracking.o\ -+ hal/phydm/phydm_noisemonitor.o\ -+ hal/phydm/phydm_beamforming.o\ -+ hal/phydm/phydm_dfs.o\ -+ hal/phydm/txbf/halcomtxbf.o\ -+ hal/phydm/txbf/haltxbfinterface.o\ -+ hal/phydm/txbf/phydm_hal_txbf_api.o\ -+ hal/phydm/phydm_adc_sampling.o\ -+ hal/phydm/phydm_ccx.o\ -+ hal/phydm/phydm_psd.o\ -+ hal/phydm/phydm_primary_cca.o\ -+ hal/phydm/phydm_cck_pd.o\ -+ hal/phydm/phydm_rssi_monitor.o\ -+ hal/phydm/phydm_auto_dbg.o\ -+ hal/phydm/phydm_math_lib.o\ -+ hal/phydm/phydm_api.o\ -+ hal/phydm/phydm_pow_train.o\ -+ hal/phydm/phydm_lna_sat.o\ -+ hal/phydm/phydm_pmac_tx_setting.o\ -+ hal/phydm/phydm_mp.o\ -+ hal/phydm/halrf/halrf.o\ -+ hal/phydm/halrf/halrf_debug.o\ -+ hal/phydm/halrf/halphyrf_ce.o\ -+ hal/phydm/halrf/halrf_powertracking_ce.o\ -+ hal/phydm/halrf/halrf_powertracking.o\ -+ hal/phydm/halrf/halrf_kfree.o -+ -+ifeq ($(CONFIG_RTL8188E), y) -+RTL871X = rtl8188e -+_PHYDM_FILES += hal/phydm/$(RTL871X)/halhwimg8188e_mac.o\ -+ hal/phydm/$(RTL871X)/halhwimg8188e_bb.o\ -+ hal/phydm/$(RTL871X)/halhwimg8188e_rf.o\ -+ hal/phydm/halrf/$(RTL871X)/halrf_8188e_ce.o\ -+ hal/phydm/$(RTL871X)/phydm_regconfig8188e.o\ -+ hal/phydm/$(RTL871X)/hal8188erateadaptive.o\ -+ hal/phydm/$(RTL871X)/phydm_rtl8188e.o -+endif -+ -+ifeq ($(CONFIG_RTL8192E), y) -+RTL871X = rtl8192e -+_PHYDM_FILES += hal/phydm/$(RTL871X)/halhwimg8192e_mac.o\ -+ hal/phydm/$(RTL871X)/halhwimg8192e_bb.o\ -+ hal/phydm/$(RTL871X)/halhwimg8192e_rf.o\ -+ hal/phydm/halrf/$(RTL871X)/halrf_8192e_ce.o\ -+ hal/phydm/$(RTL871X)/phydm_regconfig8192e.o\ -+ hal/phydm/$(RTL871X)/phydm_rtl8192e.o -+endif -+ -+ -+ifeq ($(CONFIG_RTL8812A), y) -+RTL871X = rtl8812a -+_PHYDM_FILES += hal/phydm/$(RTL871X)/halhwimg8812a_mac.o\ -+ hal/phydm/$(RTL871X)/halhwimg8812a_bb.o\ -+ hal/phydm/$(RTL871X)/halhwimg8812a_rf.o\ -+ hal/phydm/halrf/$(RTL871X)/halrf_8812a_ce.o\ -+ hal/phydm/$(RTL871X)/phydm_regconfig8812a.o\ -+ hal/phydm/$(RTL871X)/phydm_rtl8812a.o\ -+ hal/phydm/txbf/haltxbfjaguar.o -+endif -+ -+ifeq ($(CONFIG_RTL8821A), y) -+RTL871X = rtl8821a -+_PHYDM_FILES += hal/phydm/rtl8821a/halhwimg8821a_mac.o\ -+ hal/phydm/rtl8821a/halhwimg8821a_bb.o\ -+ hal/phydm/rtl8821a/halhwimg8821a_rf.o\ -+ hal/phydm/halrf/rtl8812a/halrf_8812a_ce.o\ -+ hal/phydm/halrf/rtl8821a/halrf_8821a_ce.o\ -+ hal/phydm/rtl8821a/phydm_regconfig8821a.o\ -+ hal/phydm/rtl8821a/phydm_rtl8821a.o\ -+ hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ce.o\ -+ hal/phydm/txbf/haltxbfjaguar.o -+endif -+ -+ -+ifeq ($(CONFIG_RTL8723B), y) -+RTL871X = rtl8723b -+_PHYDM_FILES += hal/phydm/$(RTL871X)/halhwimg8723b_bb.o\ -+ hal/phydm/$(RTL871X)/halhwimg8723b_mac.o\ -+ hal/phydm/$(RTL871X)/halhwimg8723b_rf.o\ -+ hal/phydm/$(RTL871X)/halhwimg8723b_mp.o\ -+ hal/phydm/$(RTL871X)/phydm_regconfig8723b.o\ -+ hal/phydm/halrf/$(RTL871X)/halrf_8723b_ce.o\ -+ hal/phydm/$(RTL871X)/phydm_rtl8723b.o -+endif -+ -+ -+ifeq ($(CONFIG_RTL8814A), y) -+RTL871X = rtl8814a -+_PHYDM_FILES += hal/phydm/$(RTL871X)/halhwimg8814a_bb.o\ -+ hal/phydm/$(RTL871X)/halhwimg8814a_mac.o\ -+ hal/phydm/$(RTL871X)/halhwimg8814a_rf.o\ -+ hal/phydm/halrf/$(RTL871X)/halrf_iqk_8814a.o\ -+ hal/phydm/$(RTL871X)/phydm_regconfig8814a.o\ -+ hal/phydm/halrf/$(RTL871X)/halrf_8814a_ce.o\ -+ hal/phydm/$(RTL871X)/phydm_rtl8814a.o\ -+ hal/phydm/txbf/haltxbf8814a.o -+endif -+ -+ -+ifeq ($(CONFIG_RTL8723C), y) -+RTL871X = rtl8703b -+_PHYDM_FILES += hal/phydm/$(RTL871X)/halhwimg8703b_bb.o\ -+ hal/phydm/$(RTL871X)/halhwimg8703b_mac.o\ -+ hal/phydm/$(RTL871X)/halhwimg8703b_rf.o\ -+ hal/phydm/$(RTL871X)/phydm_regconfig8703b.o\ -+ hal/phydm/$(RTL871X)/phydm_rtl8703b.o\ -+ hal/phydm/halrf/$(RTL871X)/halrf_8703b.o -+endif -+ -+ifeq ($(CONFIG_RTL8723D), y) -+RTL871X = rtl8723d -+_PHYDM_FILES += hal/phydm/$(RTL871X)/halhwimg8723d_bb.o\ -+ hal/phydm/$(RTL871X)/halhwimg8723d_mac.o\ -+ hal/phydm/$(RTL871X)/halhwimg8723d_rf.o\ -+ hal/phydm/$(RTL871X)/phydm_regconfig8723d.o\ -+ hal/phydm/$(RTL871X)/phydm_rtl8723d.o\ -+ hal/phydm/halrf/$(RTL871X)/halrf_8723d.o -+endif -+ -+ -+ifeq ($(CONFIG_RTL8710B), y) -+RTL871X = rtl8710b -+_PHYDM_FILES += hal/phydm/$(RTL871X)/halhwimg8710b_bb.o\ -+ hal/phydm/$(RTL871X)/halhwimg8710b_mac.o\ -+ hal/phydm/$(RTL871X)/halhwimg8710b_rf.o\ -+ hal/phydm/$(RTL871X)/phydm_regconfig8710b.o\ -+ hal/phydm/$(RTL871X)/phydm_rtl8710b.o\ -+ hal/phydm/halrf/$(RTL871X)/halrf_8710b.o -+endif -+ -+ -+ifeq ($(CONFIG_RTL8188F), y) -+RTL871X = rtl8188f -+_PHYDM_FILES += hal/phydm/$(RTL871X)/halhwimg8188f_bb.o\ -+ hal/phydm/$(RTL871X)/halhwimg8188f_mac.o\ -+ hal/phydm/$(RTL871X)/halhwimg8188f_rf.o\ -+ hal/phydm/$(RTL871X)/phydm_regconfig8188f.o\ -+ hal/phydm/halrf/$(RTL871X)/halrf_8188f.o \ -+ hal/phydm/$(RTL871X)/phydm_rtl8188f.o -+endif -+ -+ifeq ($(CONFIG_RTL8822B), y) -+RTL871X = rtl8822b -+_PHYDM_FILES += hal/phydm/$(RTL871X)/halhwimg8822b_bb.o \ -+ hal/phydm/$(RTL871X)/halhwimg8822b_mac.o \ -+ hal/phydm/$(RTL871X)/halhwimg8822b_rf.o \ -+ hal/phydm/halrf/$(RTL871X)/halrf_8822b.o \ -+ hal/phydm/$(RTL871X)/phydm_hal_api8822b.o \ -+ hal/phydm/halrf/$(RTL871X)/halrf_iqk_8822b.o \ -+ hal/phydm/halrf/$(RTL871X)/halrf_rfk_init_8822b.o \ -+ hal/phydm/$(RTL871X)/phydm_regconfig8822b.o \ -+ hal/phydm/$(RTL871X)/phydm_rtl8822b.o -+ -+_PHYDM_FILES += hal/phydm/txbf/haltxbf8822b.o -+endif -+ -+ -+ifeq ($(CONFIG_RTL8821C), y) -+RTL871X = rtl8821c -+_PHYDM_FILES += hal/phydm/$(RTL871X)/halhwimg8821c_bb.o \ -+ hal/phydm/$(RTL871X)/halhwimg8821c_mac.o \ -+ hal/phydm/$(RTL871X)/halhwimg8821c_rf.o \ -+ hal/phydm/$(RTL871X)/phydm_hal_api8821c.o \ -+ hal/phydm/$(RTL871X)/phydm_regconfig8821c.o\ -+ hal/phydm/halrf/$(RTL871X)/halrf_8821c.o\ -+ hal/phydm/halrf/$(RTL871X)/halrf_iqk_8821c.o -+endif -+ifeq ($(CONFIG_RTL8192F), y) -+RTL871X = rtl8192f -+_PHYDM_FILES += hal/phydm/$(RTL871X)/halhwimg8192f_bb.o\ -+ hal/phydm/$(RTL871X)/halhwimg8192f_mac.o\ -+ hal/phydm/$(RTL871X)/halhwimg8192f_rf.o\ -+ hal/phydm/$(RTL871X)/phydm_hal_api8192f.o\ -+ hal/phydm/$(RTL871X)/phydm_regconfig8192f.o\ -+ hal/phydm/$(RTL871X)/phydm_rtl8192f.o\ -+ hal/phydm/halrf/$(RTL871X)/halrf_8192f.o -+endif -+ -+ifeq ($(CONFIG_RTL8198F), y) -+RTL871X = rtl8198f -+_PHYDM_FILES += hal/phydm/$(RTL871X)/halhwimg8198f_bb.o\ -+ hal/phydm/$(RTL871X)/halhwimg8198f_mac.o\ -+ hal/phydm/$(RTL871X)/halhwimg8198f_rf.o\ -+ hal/phydm/$(RTL871X)/phydm_hal_api8198f.o\ -+ hal/phydm/$(RTL871X)/phydm_regconfig8198f.o -+endif -+ -+ifeq ($(CONFIG_RTL8822C), y) -+RTL871X = rtl8822c -+_PHYDM_FILES += hal/phydm/$(RTL871X)/halhwimg8822c_bb.o\ -+ hal/phydm/$(RTL871X)/halhwimg8822c_mac.o\ -+ hal/phydm/$(RTL871X)/halhwimg8822c_rf.o\ -+ hal/phydm/$(RTL871X)/phydm_hal_api8822c.o\ -+ hal/phydm/$(RTL871X)/phydm_regconfig8822c.o\ -+ hal/phydm/halrf/$(RTL871X)/halrf_8822c.o\ -+ hal/phydm/halrf/$(RTL871X)/halrf_iqk_8822c.o\ -+ hal/phydm/halrf/$(RTL871X)/halrf_tssi_8822c.o\ -+ hal/phydm/halrf/$(RTL871X)/halrf_dpk_8822c.o\ -+ hal/phydm/halrf/$(RTL871X)/halrf_rfk_init_8822c.o -+endif -+ -+ifeq ($(CONFIG_RTL8814B), y) -+RTL871X = rtl8814b -+_PHYDM_FILES += hal/phydm/$(RTL871X)/halhwimg8814b_bb.o\ -+ hal/phydm/$(RTL871X)/phydm_hal_api8814b.o\ -+ hal/phydm/$(RTL871X)/phydm_regconfig8814b.o\ -+ hal/phydm/halrf/$(RTL871X)/halrf_8814b.o \ -+ hal/phydm/halrf/$(RTL871X)/halrf_iqk_8814b.o \ -+ hal/phydm/halrf/$(RTL871X)/halrf_rfk_init_8814b.o -+endif -\ No newline at end of file -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_adaptivity.c linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_adaptivity.c -new file mode 100644 -index 000000000..086903624 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_adaptivity.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_adaptivity.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_adaptivity.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_adaptivity.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_adaptivity.c 2021-03-07 18:16:17.059956289 +0200 @@ -0,0 +1,764 @@ +/****************************************************************************** + * @@ -205941,11 +198018,9 @@ index 000000000..086903624 + return; +#endif +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_adaptivity.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_adaptivity.h -new file mode 100644 -index 000000000..147a12527 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_adaptivity.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_adaptivity.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_adaptivity.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_adaptivity.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_adaptivity.h 2021-03-07 18:16:17.059956289 +0200 @@ -0,0 +1,122 @@ +/****************************************************************************** + * @@ -206069,11 +198144,9 @@ index 000000000..147a12527 +void phydm_adaptivity(void *dm_void); + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_adc_sampling.c linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_adc_sampling.c -new file mode 100644 -index 000000000..d2278560e ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_adc_sampling.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_adc_sampling.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_adc_sampling.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_adc_sampling.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_adc_sampling.c 2021-03-07 18:16:17.059956289 +0200 @@ -0,0 +1,1291 @@ +/****************************************************************************** + * @@ -207366,11 +199439,9 @@ index 000000000..d2278560e +} + +#endif /*@endif PHYDM_LA_MODE_SUPPORT*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_adc_sampling.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_adc_sampling.h -new file mode 100644 -index 000000000..ef5520184 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_adc_sampling.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_adc_sampling.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_adc_sampling.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_adc_sampling.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_adc_sampling.h 2021-03-07 18:16:17.059956289 +0200 @@ -0,0 +1,151 @@ +/****************************************************************************** + * @@ -207523,11 +199594,9 @@ index 000000000..ef5520184 + +#endif +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_antdect.c linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_antdect.c -new file mode 100644 -index 000000000..5a44a054a ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_antdect.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_antdect.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_antdect.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_antdect.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_antdect.c 2021-03-07 18:16:17.059956289 +0200 @@ -0,0 +1,891 @@ +/****************************************************************************** + * @@ -208420,11 +200489,9 @@ index 000000000..5a44a054a +} +#endif + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_antdect.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_antdect.h -new file mode 100644 -index 000000000..f7fc75f18 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_antdect.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_antdect.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_antdect.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_antdect.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_antdect.h 2021-03-07 18:16:17.059956289 +0200 @@ -0,0 +1,78 @@ +/****************************************************************************** + * @@ -208504,11 +200571,9 @@ index 000000000..f7fc75f18 +void odm_sw_ant_detect_init(void *dm_void); +#endif +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_antdiv.c linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_antdiv.c -new file mode 100644 -index 000000000..702406e68 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_antdiv.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_antdiv.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_antdiv.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_antdiv.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_antdiv.c 2021-03-07 18:16:17.060956337 +0200 @@ -0,0 +1,5897 @@ +/****************************************************************************** + * @@ -214407,11 +206472,9 @@ index 000000000..702406e68 +} +#endif /*@#ifdef CONFIG_PHYDM_ANTENNA_DIVERSITY*/ + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_antdiv.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_antdiv.h -new file mode 100644 -index 000000000..0449ce821 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_antdiv.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_antdiv.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_antdiv.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_antdiv.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_antdiv.h 2021-03-07 18:16:17.060956337 +0200 @@ -0,0 +1,519 @@ +/****************************************************************************** + * @@ -214932,11 +206995,9 @@ index 000000000..0449ce821 +void odm_antenna_diversity(void *dm_void); +#endif /*@#ifdef CONFIG_PHYDM_ANTENNA_DIVERSITY*/ +#endif /*@#ifndef __ODMANTDIV_H__*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_api.c linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_api.c -new file mode 100644 -index 000000000..f84279c39 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_api.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_api.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_api.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_api.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_api.c 2021-03-07 18:16:17.060956337 +0200 @@ -0,0 +1,2949 @@ +/****************************************************************************** + * @@ -217887,11 +209948,9 @@ index 000000000..f84279c39 +#endif +} +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_api.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_api.h -new file mode 100644 -index 000000000..8ab47a0c5 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_api.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_api.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_api.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_api.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_api.h 2021-03-07 18:16:17.060956337 +0200 @@ -0,0 +1,186 @@ +/****************************************************************************** + * @@ -218079,11 +210138,9 @@ index 000000000..8ab47a0c5 +#endif + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_auto_dbg.c linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_auto_dbg.c -new file mode 100644 -index 000000000..1a9d95331 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_auto_dbg.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_auto_dbg.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_auto_dbg.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_auto_dbg.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_auto_dbg.c 2021-03-07 18:16:17.060956337 +0200 @@ -0,0 +1,713 @@ +/****************************************************************************** + * @@ -218798,11 +210855,9 @@ index 000000000..1a9d95331 + phydm_check_hang_init(dm); +} +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_auto_dbg.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_auto_dbg.h -new file mode 100644 -index 000000000..f6ef51d4f ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_auto_dbg.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_auto_dbg.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_auto_dbg.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_auto_dbg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_auto_dbg.h 2021-03-07 18:16:17.060956337 +0200 @@ -0,0 +1,113 @@ +/****************************************************************************** + * @@ -218917,11 +210972,9 @@ index 000000000..f6ef51d4f +void phydm_auto_dbg_engine_init(void *dm_void); +#endif +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_beamforming.c linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_beamforming.c -new file mode 100644 -index 000000000..bc4855c15 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_beamforming.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_beamforming.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_beamforming.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_beamforming.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_beamforming.c 2021-03-07 18:16:17.061956384 +0200 @@ -0,0 +1,2050 @@ +/****************************************************************************** + * @@ -220973,11 +213026,9 @@ index 000000000..bc4855c15 +} + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_beamforming.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_beamforming.h -new file mode 100644 -index 000000000..26e54c0ee ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_beamforming.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_beamforming.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_beamforming.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_beamforming.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_beamforming.h 2021-03-07 18:16:17.061956384 +0200 @@ -0,0 +1,363 @@ +/****************************************************************************** + * @@ -221342,11 +213393,3278 @@ index 000000000..26e54c0ee +#endif /*@(DM_ODM_SUPPORT_TYPE & (ODM_CE | ODM_AP))*/ +#endif /*@#ifdef PHYDM_BEAMFORMING_SUPPORT*/ +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_cck_pd.c linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_cck_pd.c -new file mode 100644 -index 000000000..8f5229abf ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_cck_pd.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm.c 2021-03-07 18:16:17.058956242 +0200 +@@ -0,0 +1,3265 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, ++ * Hsinchu 300, Taiwan. ++ * ++ * Larry Finger ++ * ++ *****************************************************************************/ ++ ++/*@************************************************************ ++ * include files ++ ************************************************************/ ++ ++#include "mp_precomp.h" ++#include "phydm_precomp.h" ++ ++const u16 phy_rate_table[] = { ++ /*@20M*/ ++ 1, 2, 5, 11, ++ 6, 9, 12, 18, 24, 36, 48, 54, ++ 6, 13, 19, 26, 39, 52, 58, 65, /*@MCS0~7*/ ++ 13, 26, 39, 52, 78, 104, 117, 130 /*@MCS8~15*/ ++}; ++ ++void phydm_traffic_load_decision(void *dm_void) ++{ ++ struct dm_struct *dm = (struct dm_struct *)dm_void; ++ u8 shift = 0; ++ ++ /*@---TP & Trafic-load calculation---*/ ++ ++ if (dm->last_tx_ok_cnt > *dm->num_tx_bytes_unicast) ++ dm->last_tx_ok_cnt = *dm->num_tx_bytes_unicast; ++ ++ if (dm->last_rx_ok_cnt > *dm->num_rx_bytes_unicast) ++ dm->last_rx_ok_cnt = *dm->num_rx_bytes_unicast; ++ ++ dm->cur_tx_ok_cnt = *dm->num_tx_bytes_unicast - dm->last_tx_ok_cnt; ++ dm->cur_rx_ok_cnt = *dm->num_rx_bytes_unicast - dm->last_rx_ok_cnt; ++ dm->last_tx_ok_cnt = *dm->num_tx_bytes_unicast; ++ dm->last_rx_ok_cnt = *dm->num_rx_bytes_unicast; ++ ++ /*@AP: <<3(8bit), >>20(10^6,M), >>0(1sec)*/ ++ shift = 17 + (PHYDM_WATCH_DOG_PERIOD - 1); ++ /*@WIN&CE: <<3(8bit), >>20(10^6,M), >>1(2sec)*/ ++ ++ dm->tx_tp = (dm->tx_tp >> 1) + (u32)((dm->cur_tx_ok_cnt >> shift) >> 1); ++ dm->rx_tp = (dm->rx_tp >> 1) + (u32)((dm->cur_rx_ok_cnt >> shift) >> 1); ++ ++ dm->total_tp = dm->tx_tp + dm->rx_tp; ++ ++ /*@[Calculate TX/RX state]*/ ++ if (dm->tx_tp > (dm->rx_tp << 1)) ++ dm->txrx_state_all = TX_STATE; ++ else if (dm->rx_tp > (dm->tx_tp << 1)) ++ dm->txrx_state_all = RX_STATE; ++ else ++ dm->txrx_state_all = BI_DIRECTION_STATE; ++ ++ /*@[Traffic load decision]*/ ++ dm->pre_traffic_load = dm->traffic_load; ++ ++ if (dm->cur_tx_ok_cnt > 1875000 || dm->cur_rx_ok_cnt > 1875000) { ++ /* @( 1.875M * 8bit ) / 2sec= 7.5M bits /sec )*/ ++ dm->traffic_load = TRAFFIC_HIGH; ++ } else if (dm->cur_tx_ok_cnt > 500000 || dm->cur_rx_ok_cnt > 500000) { ++ /*@( 0.5M * 8bit ) / 2sec = 2M bits /sec )*/ ++ dm->traffic_load = TRAFFIC_MID; ++ } else if (dm->cur_tx_ok_cnt > 100000 || dm->cur_rx_ok_cnt > 100000) { ++ /*@( 0.1M * 8bit ) / 2sec = 0.4M bits /sec )*/ ++ dm->traffic_load = TRAFFIC_LOW; ++ } else if (dm->cur_tx_ok_cnt > 25000 || dm->cur_rx_ok_cnt > 25000) { ++ /*@( 0.025M * 8bit ) / 2sec = 0.1M bits /sec )*/ ++ dm->traffic_load = TRAFFIC_ULTRA_LOW; ++ } else { ++ dm->traffic_load = TRAFFIC_NO_TP; ++ } ++ ++ /*@[Calculate consecutive idlel time]*/ ++ if (dm->traffic_load == 0) ++ dm->consecutive_idlel_time += PHYDM_WATCH_DOG_PERIOD; ++ else ++ dm->consecutive_idlel_time = 0; ++ ++ #if 0 ++ PHYDM_DBG(dm, DBG_COMMON_FLOW, ++ "cur_tx_ok_cnt = %d, cur_rx_ok_cnt = %d, last_tx_ok_cnt = %d, last_rx_ok_cnt = %d\n", ++ dm->cur_tx_ok_cnt, dm->cur_rx_ok_cnt, dm->last_tx_ok_cnt, ++ dm->last_rx_ok_cnt); ++ ++ PHYDM_DBG(dm, DBG_COMMON_FLOW, "tx_tp = %d, rx_tp = %d\n", dm->tx_tp, ++ dm->rx_tp); ++ #endif ++} ++ ++void phydm_cck_new_agc_chk(struct dm_struct *dm) ++{ ++ dm->cck_new_agc = 0; ++ ++#if ((RTL8723D_SUPPORT == 1) || (RTL8822B_SUPPORT == 1) || \ ++ (RTL8821C_SUPPORT == 1) || (RTL8197F_SUPPORT == 1) || \ ++ (RTL8710B_SUPPORT == 1) || (RTL8192F_SUPPORT == 1) || \ ++ (RTL8195B_SUPPORT == 1) || (RTL8198F_SUPPORT == 1) || \ ++ (RTL8822C_SUPPORT == 1) || (RTL8721D_SUPPORT == 1)) ++ if (dm->support_ic_type & ++ (ODM_RTL8723D | ODM_RTL8822B | ODM_RTL8821C | ODM_RTL8197F | ++ ODM_RTL8710B | ODM_RTL8192F | ODM_RTL8195B | ODM_RTL8721D)) { ++ /*@1: new agc 0: old agc*/ ++ dm->cck_new_agc = (boolean)odm_get_bb_reg(dm, R_0xa9c, BIT(17)); ++ } else if (dm->support_ic_type & (ODM_RTL8198F | ODM_RTL8822C)) { ++ /*@1: new agc 0: old agc*/ ++ dm->cck_new_agc = (boolean)odm_get_bb_reg(dm, R_0x1a9c, ++ BIT(17)); ++ } ++#endif ++} ++ ++/*select 3 or 4 bit LNA */ ++void phydm_cck_lna_bit_num_chk(struct dm_struct *dm) ++{ ++ boolean report_type = 0; ++ #if (RTL8192E_SUPPORT == 1) ++ u32 value_824, value_82c; ++ #endif ++ ++ #if (RTL8192E_SUPPORT == 1) ++ if (dm->support_ic_type & (ODM_RTL8192E)) { ++ /* @0x824[9] = 0x82C[9] = 0xA80[7] those registers setting ++ * should be equal or CCK RSSI report may be incorrect ++ */ ++ value_824 = odm_get_bb_reg(dm, R_0x824, BIT(9)); ++ value_82c = odm_get_bb_reg(dm, R_0x82c, BIT(9)); ++ ++ if (value_824 != value_82c) ++ odm_set_bb_reg(dm, R_0x82c, BIT(9), value_824); ++ odm_set_bb_reg(dm, R_0xa80, BIT(7), value_824); ++ report_type = (boolean)value_824; ++ } ++ #endif ++ ++ #if (RTL8703B_SUPPORT || RTL8723D_SUPPORT || RTL8710B_SUPPORT) ++ if (dm->support_ic_type & ++ (ODM_RTL8703B | ODM_RTL8723D | ODM_RTL8710B)) { ++ report_type = (boolean)odm_get_bb_reg(dm, R_0x950, BIT(11)); ++ ++ if (report_type != 1) ++ pr_debug("[Warning] CCK should be 4bit LNA\n"); ++ } ++ #endif ++ ++ #if (RTL8821C_SUPPORT == 1) ++ if (dm->support_ic_type & ODM_RTL8821C) { ++ if (dm->default_rf_set_8821c == SWITCH_TO_BTG) ++ report_type = 1; ++ } ++ #endif ++ ++ dm->cck_agc_report_type = report_type; ++ ++ PHYDM_DBG(dm, ODM_COMP_INIT, "cck_agc_report_type=((%d))\n", ++ dm->cck_agc_report_type); ++} ++ ++void phydm_init_cck_setting(struct dm_struct *dm) ++{ ++ u32 reg_tmp = 0; ++ u32 mask_tmp = 0; ++ ++ reg_tmp = ODM_REG(CCK_RPT_FORMAT, dm); ++ mask_tmp = ODM_BIT(CCK_RPT_FORMAT, dm); ++ dm->is_cck_high_power = (boolean)odm_get_bb_reg(dm, reg_tmp, mask_tmp); ++ ++ PHYDM_DBG(dm, ODM_COMP_INIT, "ext_lna_gain=((%d))\n", dm->ext_lna_gain); ++ ++ phydm_config_cck_rx_antenna_init(dm); ++ ++ if (dm->support_ic_type & (ODM_RTL8192F)) ++ phydm_config_cck_rx_path(dm, BB_PATH_AB); ++ else ++ phydm_config_cck_rx_path(dm, BB_PATH_A); ++ ++ phydm_cck_new_agc_chk(dm); ++ phydm_cck_lna_bit_num_chk(dm); ++ phydm_get_cck_rssi_table_from_reg(dm); ++} ++ ++void phydm_init_hw_info_by_rfe(struct dm_struct *dm) ++{ ++#if (RTL8822B_SUPPORT == 1) ++ /*@if (dm->support_ic_type & ODM_RTL8822B)*/ ++ /*@phydm_init_hw_info_by_rfe_type_8822b(dm);*/ ++#endif ++#if (RTL8821C_SUPPORT == 1) ++ if (dm->support_ic_type & ODM_RTL8821C) ++ phydm_init_hw_info_by_rfe_type_8821c(dm); ++#endif ++#if (RTL8197F_SUPPORT == 1) ++ if (dm->support_ic_type & ODM_RTL8197F) ++ phydm_init_hw_info_by_rfe_type_8197f(dm); ++#endif ++} ++ ++void phydm_common_info_self_init(struct dm_struct *dm) ++{ ++ u32 reg_tmp = 0; ++ u32 mask_tmp = 0; ++ ++ /*@BB IP Generation*/ ++ if (dm->support_ic_type & ODM_IC_JGR3_SERIES) ++ dm->ic_ip_series = PHYDM_IC_JGR3; ++ else if (dm->support_ic_type & ODM_IC_11AC_SERIES) ++ dm->ic_ip_series = PHYDM_IC_AC; ++ else if (dm->support_ic_type & ODM_IC_11N_SERIES) ++ dm->ic_ip_series = PHYDM_IC_N; ++ ++ /*@BB phy-status Generation*/ ++ if (dm->support_ic_type & PHYSTS_3RD_TYPE_IC) ++ dm->ic_phy_sts_type = PHYDM_PHYSTS_TYPE_3; ++ else if (dm->support_ic_type & PHYSTS_2ND_TYPE_IC) ++ dm->ic_phy_sts_type = PHYDM_PHYSTS_TYPE_2; ++ else ++ dm->ic_phy_sts_type = PHYDM_PHYSTS_TYPE_1; ++ ++ phydm_init_cck_setting(dm); ++ ++ reg_tmp = ODM_REG(BB_RX_PATH, dm); ++ mask_tmp = ODM_BIT(BB_RX_PATH, dm); ++ dm->rf_path_rx_enable = (u8)odm_get_bb_reg(dm, reg_tmp, mask_tmp); ++#if (DM_ODM_SUPPORT_TYPE != ODM_CE) ++ dm->is_net_closed = &dm->BOOLEAN_temp; ++ ++ phydm_init_debug_setting(dm); ++#endif ++ phydm_init_soft_ml_setting(dm); ++ ++ dm->phydm_sys_up_time = 0; ++ ++ if (dm->support_ic_type & ODM_IC_1SS) ++ dm->num_rf_path = 1; ++ else if (dm->support_ic_type & ODM_IC_2SS) ++ dm->num_rf_path = 2; ++ #if 0 ++ /* @RTK do not has IC which is equipped with 3 RF paths, ++ * so ODM_IC_3SS is an enpty macro and result in coverity check errors ++ */ ++ else if (dm->support_ic_type & ODM_IC_3SS) ++ dm->num_rf_path = 3; ++ #endif ++ else if (dm->support_ic_type & ODM_IC_4SS) ++ dm->num_rf_path = 4; ++ else ++ dm->num_rf_path = 1; ++ ++ phydm_trx_antenna_setting_init(dm, dm->num_rf_path); ++ ++ dm->tx_rate = 0xFF; ++ dm->rssi_min_by_path = 0xFF; ++ ++ dm->number_linked_client = 0; ++ dm->pre_number_linked_client = 0; ++ dm->number_active_client = 0; ++ dm->pre_number_active_client = 0; ++ ++ dm->last_tx_ok_cnt = 0; ++ dm->last_rx_ok_cnt = 0; ++ dm->tx_tp = 0; ++ dm->rx_tp = 0; ++ dm->total_tp = 0; ++ dm->traffic_load = TRAFFIC_LOW; ++ ++ dm->nbi_set_result = 0; ++ dm->is_init_hw_info_by_rfe = false; ++ dm->pre_dbg_priority = DBGPORT_RELEASE; ++ dm->tp_active_th = 5; ++ dm->disable_phydm_watchdog = 0; ++ ++ dm->u8_dummy = 0xf; ++ dm->u16_dummy = 0xffff; ++ dm->u32_dummy = 0xffffffff; ++ ++ dm->pause_lv_table.lv_cckpd = PHYDM_PAUSE_RELEASE; ++ dm->pause_lv_table.lv_dig = PHYDM_PAUSE_RELEASE; ++} ++ ++void phydm_cmn_sta_info_update(void *dm_void, u8 macid) ++{ ++ struct dm_struct *dm = (struct dm_struct *)dm_void; ++ struct cmn_sta_info *sta = dm->phydm_sta_info[macid]; ++ struct ra_sta_info *ra = NULL; ++ ++ if (is_sta_active(sta)) { ++ ra = &sta->ra_info; ++ } else { ++ PHYDM_DBG(dm, DBG_RA_MASK, "[Warning] %s invalid sta_info\n", ++ __func__); ++ return; ++ } ++ ++ PHYDM_DBG(dm, DBG_RA_MASK, "%s ======>\n", __func__); ++ PHYDM_DBG(dm, DBG_RA_MASK, "MACID=%d\n", sta->mac_id); ++ ++ /*@[Calculate TX/RX state]*/ ++ if (sta->tx_moving_average_tp > (sta->rx_moving_average_tp << 1)) ++ ra->txrx_state = TX_STATE; ++ else if (sta->rx_moving_average_tp > (sta->tx_moving_average_tp << 1)) ++ ra->txrx_state = RX_STATE; ++ else ++ ra->txrx_state = BI_DIRECTION_STATE; ++ ++ ra->is_noisy = dm->noisy_decision; ++} ++ ++void phydm_common_info_self_update(struct dm_struct *dm) ++{ ++ u8 sta_cnt = 0, num_active_client = 0; ++ u32 i, one_entry_macid = 0; ++ u32 ma_rx_tp = 0; ++ u32 tp_diff = 0; ++ struct cmn_sta_info *sta; ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) ++ ++ PADAPTER adapter = (PADAPTER)dm->adapter; ++ ++ PMGNT_INFO mgnt_info = &((PADAPTER)adapter)->MgntInfo; ++ ++ sta = dm->phydm_sta_info[0]; ++ if (mgnt_info->mAssoc) { ++ sta->dm_ctrl |= STA_DM_CTRL_ACTIVE; ++ for (i = 0; i < 6; i++) ++ sta->mac_addr[i] = mgnt_info->Bssid[i]; ++ } else if (GetFirstClientPort(adapter)) { ++ //void *client_adapter = GetFirstClientPort(adapter); ++ struct _ADAPTER *client_adapter = GetFirstClientPort(adapter); ++ ++ sta->dm_ctrl |= STA_DM_CTRL_ACTIVE; ++ for (i = 0; i < 6; i++) ++ sta->mac_addr[i] = client_adapter->MgntInfo.Bssid[i]; ++ } else { ++ sta->dm_ctrl = sta->dm_ctrl & (~STA_DM_CTRL_ACTIVE); ++ for (i = 0; i < 6; i++) ++ sta->mac_addr[i] = 0; ++ } ++ ++ /* STA mode is linked to AP */ ++ if (is_sta_active(sta) && !ACTING_AS_AP(adapter)) ++ dm->bsta_state = true; ++ else ++ dm->bsta_state = false; ++#endif ++ ++ for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) { ++ sta = dm->phydm_sta_info[i]; ++ if (is_sta_active(sta)) { ++ sta_cnt++; ++ ++ if (sta_cnt == 1) ++ one_entry_macid = i; ++ ++ phydm_cmn_sta_info_update(dm, (u8)i); ++ #ifdef PHYDM_BEAMFORMING_SUPPORT ++ /*@phydm_get_txbf_device_num(dm, (u8)i);*/ ++ #endif ++ ++ ma_rx_tp = sta->rx_moving_average_tp + ++ sta->tx_moving_average_tp; ++ ++ PHYDM_DBG(dm, DBG_COMMON_FLOW, ++ "TP[%d]: ((%d )) bit/sec\n", i, ma_rx_tp); ++ ++ if (ma_rx_tp > ACTIVE_TP_THRESHOLD) ++ num_active_client++; ++ } ++ } ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) ++ dm->is_linked = (sta_cnt != 0) ? true : false; ++#endif ++ ++ if (sta_cnt == 1) { ++ dm->is_one_entry_only = true; ++ dm->one_entry_macid = one_entry_macid; ++ dm->one_entry_tp = ma_rx_tp; ++ ++ dm->tp_active_occur = 0; ++ ++ PHYDM_DBG(dm, DBG_COMMON_FLOW, ++ "one_entry_tp=((%d)), pre_one_entry_tp=((%d))\n", ++ dm->one_entry_tp, dm->pre_one_entry_tp); ++ ++ if (dm->one_entry_tp > dm->pre_one_entry_tp && ++ dm->pre_one_entry_tp <= 2) { ++ tp_diff = dm->one_entry_tp - dm->pre_one_entry_tp; ++ ++ if (tp_diff > dm->tp_active_th) ++ dm->tp_active_occur = 1; ++ } ++ dm->pre_one_entry_tp = dm->one_entry_tp; ++ } else { ++ dm->is_one_entry_only = false; ++ } ++ ++ dm->pre_number_linked_client = dm->number_linked_client; ++ dm->pre_number_active_client = dm->number_active_client; ++ ++ dm->number_linked_client = sta_cnt; ++ dm->number_active_client = num_active_client; ++ ++ /*Traffic load information update*/ ++ phydm_traffic_load_decision(dm); ++ ++ dm->phydm_sys_up_time += PHYDM_WATCH_DOG_PERIOD; ++ ++ dm->is_dfs_band = phydm_is_dfs_band(dm); ++ dm->phy_dbg_info.show_phy_sts_cnt = 0; ++} ++ ++void phydm_common_info_self_reset(struct dm_struct *dm) ++{ ++ struct odm_phy_dbg_info *dbg_t = &dm->phy_dbg_info; ++ ++ dbg_t->beacon_cnt_in_period = dbg_t->num_qry_beacon_pkt; ++ dbg_t->num_qry_beacon_pkt = 0; ++ ++ dm->rxsc_l = 0xff; ++ dm->rxsc_20 = 0xff; ++ dm->rxsc_40 = 0xff; ++ dm->rxsc_80 = 0xff; ++} ++ ++void * ++phydm_get_structure(struct dm_struct *dm, u8 structure_type) ++ ++{ ++ void *structure = NULL; ++ ++ switch (structure_type) { ++ case PHYDM_FALSEALMCNT: ++ structure = &dm->false_alm_cnt; ++ break; ++ ++ case PHYDM_CFOTRACK: ++ structure = &dm->dm_cfo_track; ++ break; ++ ++ case PHYDM_ADAPTIVITY: ++ structure = &dm->adaptivity; ++ break; ++ ++ case PHYDM_DFS: ++ structure = &dm->dfs; ++ break; ++ ++ default: ++ break; ++ } ++ ++ return structure; ++} ++ ++void phydm_phy_info_update(struct dm_struct *dm) ++{ ++#if (RTL8822B_SUPPORT == 1) ++ if (dm->support_ic_type == ODM_RTL8822B) ++ dm->phy_dbg_info.condi_num = phydm_get_condi_num_8822b(dm); ++#endif ++} ++ ++void phydm_hw_setting(struct dm_struct *dm) ++{ ++#if (RTL8821A_SUPPORT == 1) ++ if (dm->support_ic_type & ODM_RTL8821) ++ odm_hw_setting_8821a(dm); ++#endif ++ ++#if 0 /* TODO: implementation done but may not work and do nothing with current flags. Commenting the code to match previous version behavior*/ ++#if (RTL8814A_SUPPORT == 1) ++ if (dm->support_ic_type & ODM_RTL8814A) ++ phydm_hwsetting_8814a(dm); ++#endif ++#endif ++ ++#if (RTL8822B_SUPPORT == 1) ++ if (dm->support_ic_type & ODM_RTL8822B) ++ phydm_hwsetting_8822b(dm); ++#endif ++ ++#if (RTL8812A_SUPPORT == 1) ++ if (dm->support_ic_type & ODM_RTL8812) ++ phydm_hwsetting_8812a(dm); ++#endif ++ ++#if (RTL8197F_SUPPORT == 1) ++ if (dm->support_ic_type & ODM_RTL8197F) ++ phydm_hwsetting_8197f(dm); ++#endif ++ ++#if (RTL8192F_SUPPORT == 1) ++ if (dm->support_ic_type & ODM_RTL8192F) ++ phydm_hwsetting_8192f(dm); ++#endif ++} ++ ++#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN)) ++u64 phydm_supportability_init_win( ++ void *dm_void) ++{ ++ struct dm_struct *dm = (struct dm_struct *)dm_void; ++ u64 support_ability = 0; ++ ++ switch (dm->support_ic_type) { ++/*@---------------N Series--------------------*/ ++#if (RTL8188E_SUPPORT) ++ case ODM_RTL8188E: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ /*ODM_BB_DYNAMIC_TXPWR |*/ ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR | ++ ODM_BB_PRIMARY_CCA; ++ break; ++#endif ++ ++#if (RTL8192E_SUPPORT) ++ case ODM_RTL8192E: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ /*ODM_BB_DYNAMIC_TXPWR |*/ ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR | ++ ODM_BB_PRIMARY_CCA; ++ break; ++#endif ++ ++#if (RTL8723B_SUPPORT) ++ case ODM_RTL8723B: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ /*ODM_BB_DYNAMIC_TXPWR |*/ ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR | ++ ODM_BB_PRIMARY_CCA; ++ break; ++#endif ++ ++#if (RTL8703B_SUPPORT) ++ case ODM_RTL8703B: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ /*ODM_BB_DYNAMIC_TXPWR |*/ ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR; ++ break; ++#endif ++ ++#if (RTL8723D_SUPPORT) ++ case ODM_RTL8723D: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ /*ODM_BB_DYNAMIC_TXPWR |*/ ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ ODM_BB_PWR_TRAIN | ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR; ++ break; ++#endif ++ ++#if (RTL8710B_SUPPORT) ++ case ODM_RTL8710B: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ /*ODM_BB_DYNAMIC_TXPWR |*/ ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ ODM_BB_PWR_TRAIN | ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR; ++ break; ++#endif ++ ++#if (RTL8188F_SUPPORT) ++ case ODM_RTL8188F: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ /*ODM_BB_DYNAMIC_TXPWR |*/ ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR; ++ break; ++#endif ++ ++#if (RTL8192F_SUPPORT) ++ case ODM_RTL8192F: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ ODM_BB_PWR_TRAIN | ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ADAPTIVE_SOML | ++ ODM_BB_ENV_MONITOR; ++ /*ODM_BB_LNA_SAT_CHK |*/ ++ /*ODM_BB_PRIMARY_CCA*/ ++ ++ break; ++#endif ++ ++/*@---------------AC Series-------------------*/ ++ ++#if (RTL8812A_SUPPORT || RTL8821A_SUPPORT) ++ case ODM_RTL8812: ++ case ODM_RTL8821: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ ODM_BB_DYNAMIC_TXPWR | ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR; ++ break; ++#endif ++ ++#if (RTL8814A_SUPPORT) ++ case ODM_RTL8814A: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ ODM_BB_DYNAMIC_TXPWR | ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR; ++ break; ++#endif ++ ++#if (RTL8822B_SUPPORT) ++ case ODM_RTL8822B: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ /*ODM_BB_DYNAMIC_TXPWR |*/ ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*ODM_BB_PWR_TRAIN |*/ ++ /*ODM_BB_ADAPTIVE_SOML |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR; ++ break; ++#endif ++ ++#if (RTL8821C_SUPPORT) ++ case ODM_RTL8821C: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ /*ODM_BB_DYNAMIC_TXPWR |*/ ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR; ++ break; ++#endif ++ ++/*@---------------JGR3 Series-------------------*/ ++ ++#if (RTL8822C_SUPPORT) ++ case ODM_RTL8822C: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ /* ODM_BB_DYNAMIC_TXPWR |*/ ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR; ++ break; ++#endif ++ ++#if (RTL8814B_SUPPORT) ++ case ODM_RTL8814B: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ /*ODM_BB_DYNAMIC_TXPWR |*/ ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ /*ODM_BB_CCK_PD |*/ ++ /*ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING; ++ /*ODM_BB_ENV_MONITOR;*/ ++ break; ++#endif ++ ++ default: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ /*ODM_BB_DYNAMIC_TXPWR |*/ ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR; ++ ++ pr_debug("[Warning] Supportability Init Warning !!!\n"); ++ break; ++ } ++ ++ return support_ability; ++} ++#endif ++ ++#if (DM_ODM_SUPPORT_TYPE & (ODM_CE)) ++u64 phydm_supportability_init_ce(void *dm_void) ++{ ++ struct dm_struct *dm = (struct dm_struct *)dm_void; ++ u64 support_ability = 0; ++ ++ switch (dm->support_ic_type) { ++/*@---------------N Series--------------------*/ ++#if (RTL8188E_SUPPORT) ++ case ODM_RTL8188E: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ /*@ODM_BB_DYNAMIC_TXPWR |*/ ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*@ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR | ++ ODM_BB_PRIMARY_CCA; ++ break; ++#endif ++ ++#if (RTL8192E_SUPPORT) ++ case ODM_RTL8192E: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ /*@ODM_BB_DYNAMIC_TXPWR |*/ ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*@ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR | ++ ODM_BB_PRIMARY_CCA; ++ break; ++#endif ++ ++#if (RTL8723B_SUPPORT) ++ case ODM_RTL8723B: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ /*@ODM_BB_DYNAMIC_TXPWR |*/ ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*@ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR | ++ ODM_BB_PRIMARY_CCA; ++ break; ++#endif ++ ++#if (RTL8703B_SUPPORT) ++ case ODM_RTL8703B: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ /*@ODM_BB_DYNAMIC_TXPWR |*/ ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*@ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR; ++ break; ++#endif ++ ++#if (RTL8723D_SUPPORT) ++ case ODM_RTL8723D: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ /*@ODM_BB_DYNAMIC_TXPWR |*/ ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ ODM_BB_PWR_TRAIN | ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR; ++ break; ++#endif ++ ++#if (RTL8710B_SUPPORT) ++ case ODM_RTL8710B: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ /*@ODM_BB_DYNAMIC_TXPWR |*/ ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*@ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR; ++ break; ++#endif ++ ++#if (RTL8188F_SUPPORT) ++ case ODM_RTL8188F: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ /*@ODM_BB_DYNAMIC_TXPWR |*/ ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*@ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR; ++ break; ++#endif ++ ++#if (RTL8192F_SUPPORT) ++ case ODM_RTL8192F: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ ODM_BB_PWR_TRAIN | ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ /*@ODM_BB_ADAPTIVE_SOML |*/ ++ ODM_BB_ENV_MONITOR; ++ /*@ODM_BB_LNA_SAT_CHK |*/ ++ /*@ODM_BB_PRIMARY_CCA*/ ++ break; ++#endif ++/*@---------------AC Series-------------------*/ ++ ++#if (RTL8812A_SUPPORT || RTL8821A_SUPPORT) ++ case ODM_RTL8812: ++ case ODM_RTL8821: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ /*@ODM_BB_DYNAMIC_TXPWR |*/ ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*@ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR; ++ break; ++#endif ++ ++#if (RTL8814A_SUPPORT) ++ case ODM_RTL8814A: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ /*@ODM_BB_DYNAMIC_TXPWR |*/ ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*@ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR; ++ break; ++#endif ++ ++#if (RTL8822B_SUPPORT) ++ case ODM_RTL8822B: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ /*@ODM_BB_DYNAMIC_TXPWR |*/ ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*@ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR; ++ break; ++#endif ++ ++#if (RTL8821C_SUPPORT) ++ case ODM_RTL8821C: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ /*@ODM_BB_DYNAMIC_TXPWR |*/ ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*@ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR; ++ break; ++#endif ++ ++/*@---------------JGR3 Series-------------------*/ ++ ++#if (RTL8822C_SUPPORT) ++ case ODM_RTL8822C: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ /* ODM_BB_DYNAMIC_TXPWR |*/ ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR; ++ break; ++#endif ++ ++#if (RTL8814B_SUPPORT) ++ case ODM_RTL8814B: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ /*@ODM_BB_DYNAMIC_TXPWR |*/ ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR; ++ /*ODM_BB_CCK_PD |*/ ++ /*@ODM_BB_PWR_TRAIN |*/ ++ /*ODM_BB_RATE_ADAPTIVE |*/ ++ /*ODM_BB_CFO_TRACKING |*/ ++ /*ODM_BB_ENV_MONITOR;*/ ++ break; ++#endif ++ ++ default: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ /*@ODM_BB_DYNAMIC_TXPWR |*/ ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*@ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR; ++ ++ pr_debug("[Warning] Supportability Init Warning !!!\n"); ++ break; ++ } ++ ++ return support_ability; ++} ++#endif ++ ++#if (DM_ODM_SUPPORT_TYPE & (ODM_AP)) ++u64 phydm_supportability_init_ap( ++ void *dm_void) ++{ ++ struct dm_struct *dm = (struct dm_struct *)dm_void; ++ u64 support_ability = 0; ++ ++ switch (dm->support_ic_type) { ++/*@---------------N Series--------------------*/ ++#if (RTL8188E_SUPPORT) ++ case ODM_RTL8188E: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR | ++ ODM_BB_PRIMARY_CCA; ++ break; ++#endif ++ ++#if (RTL8192E_SUPPORT) ++ case ODM_RTL8192E: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR | ++ ODM_BB_PRIMARY_CCA; ++ break; ++#endif ++ ++#if (RTL8723B_SUPPORT) ++ case ODM_RTL8723B: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR; ++ break; ++#endif ++ ++#if (RTL8198F_SUPPORT || RTL8197F_SUPPORT) ++ case ODM_RTL8198F: ++ support_ability |= ++ /*ODM_BB_DIG |*/ ++ ODM_BB_RA_MASK | ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR; ++ /*ODM_BB_CCK_PD |*/ ++ /*ODM_BB_PWR_TRAIN |*/ ++ /*ODM_BB_RATE_ADAPTIVE |*/ ++ /*ODM_BB_CFO_TRACKING |*/ ++ /*ODM_BB_ADAPTIVE_SOML |*/ ++ /*ODM_BB_ENV_MONITOR |*/ ++ /*ODM_BB_LNA_SAT_CHK |*/ ++ /*ODM_BB_PRIMARY_CCA;*/ ++ break; ++ case ODM_RTL8197F: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ADAPTIVE_SOML | ++ ODM_BB_ENV_MONITOR | ++ ODM_BB_LNA_SAT_CHK | ++ ODM_BB_PRIMARY_CCA; ++ break; ++#endif ++ ++#if (RTL8192F_SUPPORT) ++ case ODM_RTL8192F: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ /*ODM_BB_CFO_TRACKING |*/ ++ ODM_BB_ADAPTIVE_SOML | ++ /*ODM_BB_ENV_MONITOR |*/ ++ /*ODM_BB_LNA_SAT_CHK |*/ ++ /*ODM_BB_PRIMARY_CCA |*/ ++ 0; ++ break; ++#endif ++ ++/*@---------------AC Series-------------------*/ ++ ++#if (RTL8881A_SUPPORT) ++ case ODM_RTL8881A: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR; ++ break; ++#endif ++ ++#if (RTL8814A_SUPPORT) ++ case ODM_RTL8814A: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR; ++ break; ++#endif ++ ++#if (RTL8822B_SUPPORT) ++ case ODM_RTL8822B: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*ODM_BB_PWR_TRAIN |*/ ++ /*ODM_BB_ADAPTIVE_SOML |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR; ++ break; ++#endif ++ ++#if (RTL8821C_SUPPORT) ++ case ODM_RTL8821C: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR; ++ ++ break; ++#endif ++ ++/*@---------------JGR3 Series-------------------*/ ++ ++#if (RTL8814B_SUPPORT) ++ case ODM_RTL8814B: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR; ++ /*ODM_BB_CCK_PD |*/ ++ /*ODM_BB_PWR_TRAIN |*/ ++ /*ODM_BB_RATE_ADAPTIVE |*/ ++ /*ODM_BB_CFO_TRACKING |*/ ++ /*ODM_BB_ENV_MONITOR;*/ ++ break; ++#endif ++ ++ default: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR; ++ ++ pr_debug("[Warning] Supportability Init Warning !!!\n"); ++ break; ++ } ++ ++#if 0 ++ /*@[Config Antenna Diveristy]*/ ++ if (*dm->enable_antdiv) ++ support_ability |= ODM_BB_ANT_DIV; ++ ++ /*@[Config Adaptivity]*/ ++ if (*dm->enable_adaptivity) ++ support_ability |= ODM_BB_ADAPTIVITY; ++#endif ++ ++ return support_ability; ++} ++#endif ++ ++#if (DM_ODM_SUPPORT_TYPE & (ODM_IOT)) ++u64 phydm_supportability_init_iot( ++ void *dm_void) ++{ ++ struct dm_struct *dm = (struct dm_struct *)dm_void; ++ u64 support_ability = 0; ++ ++ switch (dm->support_ic_type) { ++#if (RTL8710B_SUPPORT) ++ case ODM_RTL8710B: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ /*ODM_BB_DYNAMIC_TXPWR |*/ ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR; ++ break; ++#endif ++ ++#if (RTL8195A_SUPPORT) ++ case ODM_RTL8195A: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ /*ODM_BB_DYNAMIC_TXPWR |*/ ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR; ++ break; ++#endif ++ ++#if (RTL8195B_SUPPORT) ++ case ODM_RTL8195B: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ /*ODM_BB_DYNAMIC_TXPWR |*/ ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING; ++ /*ODM_BB_ENV_MONITOR*/ ++ break; ++#endif ++ ++#if (RTL8721D_SUPPORT) ++ case ODM_RTL8721D: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ /*ODM_BB_DYNAMIC_TXPWR |*/ ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR; ++ break; ++#endif ++ ++ default: ++ support_ability |= ++ ODM_BB_DIG | ++ ODM_BB_RA_MASK | ++ /*ODM_BB_DYNAMIC_TXPWR |*/ ++ ODM_BB_FA_CNT | ++ ODM_BB_RSSI_MONITOR | ++ ODM_BB_CCK_PD | ++ /*ODM_BB_PWR_TRAIN |*/ ++ ODM_BB_RATE_ADAPTIVE | ++ ODM_BB_CFO_TRACKING | ++ ODM_BB_ENV_MONITOR; ++ ++ pr_debug("[Warning] Supportability Init Warning !!!\n"); ++ break; ++ } ++ ++ return support_ability; ++} ++#endif ++ ++void phydm_fwoffload_ability_init(struct dm_struct *dm, ++ enum phydm_offload_ability offload_ability) ++{ ++ switch (offload_ability) { ++ case PHYDM_PHY_PARAM_OFFLOAD: ++ if (dm->support_ic_type & ++ (ODM_RTL8814A | ODM_RTL8822B | ODM_RTL8821C)) ++ dm->fw_offload_ability |= PHYDM_PHY_PARAM_OFFLOAD; ++ break; ++ ++ case PHYDM_RF_IQK_OFFLOAD: ++ dm->fw_offload_ability |= PHYDM_RF_IQK_OFFLOAD; ++ break; ++ ++ default: ++ PHYDM_DBG(dm, ODM_COMP_INIT, "fwofflad, wrong init type!!\n"); ++ break; ++ } ++ ++ PHYDM_DBG(dm, ODM_COMP_INIT, "fw_offload_ability = %x\n", ++ dm->fw_offload_ability); ++} ++ ++void phydm_fwoffload_ability_clear(struct dm_struct *dm, ++ enum phydm_offload_ability offload_ability) ++{ ++ switch (offload_ability) { ++ case PHYDM_PHY_PARAM_OFFLOAD: ++ if (dm->support_ic_type & ++ (ODM_RTL8814A | ODM_RTL8822B | ODM_RTL8821C)) ++ dm->fw_offload_ability &= (~PHYDM_PHY_PARAM_OFFLOAD); ++ break; ++ ++ case PHYDM_RF_IQK_OFFLOAD: ++ dm->fw_offload_ability &= (~PHYDM_RF_IQK_OFFLOAD); ++ break; ++ ++ default: ++ PHYDM_DBG(dm, ODM_COMP_INIT, "fwofflad, wrong init type!!\n"); ++ break; ++ } ++ ++ PHYDM_DBG(dm, ODM_COMP_INIT, "fw_offload_ability = %x\n", ++ dm->fw_offload_ability); ++} ++ ++void phydm_supportability_init(void *dm_void) ++{ ++ struct dm_struct *dm = (struct dm_struct *)dm_void; ++ u64 support_ability; ++ ++ if (*dm->mp_mode) { ++ support_ability = 0; ++ } else { ++ #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN)) ++ support_ability = phydm_supportability_init_win(dm); ++ #elif (DM_ODM_SUPPORT_TYPE & (ODM_AP)) ++ support_ability = phydm_supportability_init_ap(dm); ++ #elif(DM_ODM_SUPPORT_TYPE & (ODM_CE)) ++ support_ability = phydm_supportability_init_ce(dm); ++ #elif(DM_ODM_SUPPORT_TYPE & (ODM_IOT)) ++ support_ability = phydm_supportability_init_iot(dm); ++ #endif ++ ++ /*@[Config Antenna Diversity]*/ ++ if (IS_FUNC_EN(dm->enable_antdiv)) ++ support_ability |= ODM_BB_ANT_DIV; ++ ++ /*@[Config TXpath Diversity]*/ ++ if (IS_FUNC_EN(dm->enable_pathdiv)) ++ support_ability |= ODM_BB_PATH_DIV; ++ ++ /*@[Config Adaptive SOML]*/ ++ if (IS_FUNC_EN(dm->en_adap_soml)) ++ support_ability |= ODM_BB_ADAPTIVE_SOML; ++ ++ /* @[Config Adaptivity]*/ ++ if (IS_FUNC_EN(dm->enable_adaptivity)) ++ support_ability |= ODM_BB_ADAPTIVITY; ++ } ++ odm_cmn_info_init(dm, ODM_CMNINFO_ABILITY, support_ability); ++ PHYDM_DBG(dm, ODM_COMP_INIT, "IC=0x%x, mp=%d, Supportability=0x%llx\n", ++ dm->support_ic_type, *dm->mp_mode, dm->support_ability); ++} ++ ++void phydm_rfe_init(void *dm_void) ++{ ++ struct dm_struct *dm = (struct dm_struct *)dm_void; ++ ++ PHYDM_DBG(dm, ODM_COMP_INIT, "RFE_Init\n"); ++#if (RTL8822B_SUPPORT == 1) ++ if (dm->support_ic_type == ODM_RTL8822B) ++ phydm_rfe_8822b_init(dm); ++#endif ++} ++ ++void phydm_dm_early_init(struct dm_struct *dm) ++{ ++ ++} ++ ++void odm_dm_init(struct dm_struct *dm) ++{ ++ halrf_init(dm); ++ phydm_supportability_init(dm); ++ phydm_rfe_init(dm); ++ phydm_common_info_self_init(dm); ++ phydm_rx_phy_status_init(dm); ++#ifdef PHYDM_AUTO_DEGBUG ++ phydm_auto_dbg_engine_init(dm); ++#endif ++ phydm_dig_init(dm); ++#ifdef PHYDM_SUPPORT_CCKPD ++ phydm_cck_pd_init(dm); ++#endif ++ phydm_env_monitor_init(dm); ++ phydm_adaptivity_init(dm); ++ phydm_ra_info_init(dm); ++ phydm_rssi_monitor_init(dm); ++ phydm_cfo_tracking_init(dm); ++ phydm_rf_init(dm); ++ phydm_dc_cancellation(dm); ++#ifdef PHYDM_TXA_CALIBRATION ++ phydm_txcurrentcalibration(dm); ++ phydm_get_pa_bias_offset(dm); ++#endif ++#ifdef CONFIG_PHYDM_ANTENNA_DIVERSITY ++ odm_antenna_diversity_init(dm); ++#endif ++#ifdef CONFIG_ADAPTIVE_SOML ++ phydm_adaptive_soml_init(dm); ++#endif ++#ifdef CONFIG_PATH_DIVERSITY ++ phydm_tx_path_diversity_init(dm); ++#endif ++#ifdef CONFIG_DYNAMIC_TX_TWR ++ phydm_dynamic_tx_power_init(dm); ++#endif ++#if (PHYDM_LA_MODE_SUPPORT == 1) ++ adc_smp_init(dm); ++#endif ++ ++#ifdef PHYDM_BEAMFORMING_VERSION1 ++ phydm_beamforming_init(dm); ++#endif ++ ++#if (RTL8188E_SUPPORT == 1) ++ odm_ra_info_init_all(dm); ++#endif ++#ifdef PHYDM_PRIMARY_CCA ++ phydm_primary_cca_init(dm); ++#endif ++#ifdef CONFIG_PSD_TOOL ++ phydm_psd_init(dm); ++#endif ++ ++#ifdef CONFIG_SMART_ANTENNA ++ phydm_smt_ant_init(dm); ++#endif ++#ifdef PHYDM_LNA_SAT_CHK_SUPPORT ++ phydm_lna_sat_check_init(dm); ++#endif ++#ifdef CONFIG_MCC_DM ++ #if (RTL8822B_SUPPORT == 1) ++ phydm_mcc_init(dm); ++ #endif ++#endif ++} ++ ++void odm_dm_reset(struct dm_struct *dm) ++{ ++ struct phydm_dig_struct *dig_t = &dm->dm_dig_table; ++ ++ #ifdef CONFIG_PHYDM_ANTENNA_DIVERSITY ++ odm_ant_div_reset(dm); ++ #endif ++ phydm_set_edcca_threshold_api(dm, dig_t->cur_ig_value); ++} ++ ++void phydm_supportability_en(void *dm_void, char input[][16], u32 *_used, ++ char *output, u32 *_out_len) ++{ ++ struct dm_struct *dm = (struct dm_struct *)dm_void; ++ u32 dm_value[10] = {0}; ++ u64 pre_support_ability, one = 1; ++ u64 comp = 0; ++ u32 used = *_used; ++ u32 out_len = *_out_len; ++ u8 i; ++ ++ for (i = 0; i < 5; i++) { ++ if (input[i + 1]) ++ PHYDM_SSCANF(input[i + 1], DCMD_DECIMAL, &dm_value[i]); ++ } ++ ++ pre_support_ability = dm->support_ability; ++ comp = dm->support_ability; ++ ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "\n================================\n"); ++ ++ if (dm_value[0] == 100) { ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "[Supportability] PhyDM Selection\n"); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "================================\n"); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "00. (( %s ))DIG\n", ++ ((comp & ODM_BB_DIG) ? ("V") : ("."))); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "01. (( %s ))RA_MASK\n", ++ ((comp & ODM_BB_RA_MASK) ? ("V") : ("."))); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "02. (( %s ))DYN_TXPWR\n", ++ ((comp & ODM_BB_DYNAMIC_TXPWR) ? ("V") : ("."))); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "03. (( %s ))FA_CNT\n", ++ ((comp & ODM_BB_FA_CNT) ? ("V") : ("."))); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "04. (( %s ))RSSI_MNTR\n", ++ ((comp & ODM_BB_RSSI_MONITOR) ? ("V") : ("."))); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "05. (( %s ))CCK_PD\n", ++ ((comp & ODM_BB_CCK_PD) ? ("V") : ("."))); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "06. (( %s ))ANT_DIV\n", ++ ((comp & ODM_BB_ANT_DIV) ? ("V") : ("."))); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "07. (( %s ))SMT_ANT\n", ++ ((comp & ODM_BB_SMT_ANT) ? ("V") : ("."))); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "08. (( %s ))PWR_TRAIN\n", ++ ((comp & ODM_BB_PWR_TRAIN) ? ("V") : ("."))); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "09. (( %s ))RA\n", ++ ((comp & ODM_BB_RATE_ADAPTIVE) ? ("V") : ("."))); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "10. (( %s ))PATH_DIV\n", ++ ((comp & ODM_BB_PATH_DIV) ? ("V") : ("."))); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "11. (( %s ))DFS\n", ++ ((comp & ODM_BB_DFS) ? ("V") : ("."))); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "12. (( %s ))DYN_ARFR\n", ++ ((comp & ODM_BB_DYNAMIC_ARFR) ? ("V") : ("."))); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "13. (( %s ))ADAPTIVITY\n", ++ ((comp & ODM_BB_ADAPTIVITY) ? ("V") : ("."))); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "14. (( %s ))CFO_TRACK\n", ++ ((comp & ODM_BB_CFO_TRACKING) ? ("V") : ("."))); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "15. (( %s ))ENV_MONITOR\n", ++ ((comp & ODM_BB_ENV_MONITOR) ? ("V") : ("."))); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "16. (( %s ))PRI_CCA\n", ++ ((comp & ODM_BB_PRIMARY_CCA) ? ("V") : ("."))); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "17. (( %s ))ADPTV_SOML\n", ++ ((comp & ODM_BB_ADAPTIVE_SOML) ? ("V") : ("."))); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "18. (( %s ))LNA_SAT_CHK\n", ++ ((comp & ODM_BB_LNA_SAT_CHK) ? ("V") : ("."))); ++ ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "================================\n"); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "[Supportability] PhyDM offload ability\n"); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "================================\n"); ++ ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "00. (( %s ))PHY PARAM OFFLOAD\n", ++ ((dm->fw_offload_ability & PHYDM_PHY_PARAM_OFFLOAD) ? ++ ("V") : ("."))); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "01. (( %s ))RF IQK OFFLOAD\n", ++ ((dm->fw_offload_ability & PHYDM_RF_IQK_OFFLOAD) ? ++ ("V") : ("."))); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "================================\n"); ++ ++ } else if (dm_value[0] == 101) { ++ dm->support_ability = 0; ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "Disable all support_ability components\n"); ++ } else { ++ if (dm_value[1] == 1) { /* @enable */ ++ dm->support_ability |= (one << dm_value[0]); ++ } else if (dm_value[1] == 2) {/* @disable */ ++ dm->support_ability &= ~(one << dm_value[0]); ++ } else { ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "[Warning!!!] 1:enable, 2:disable\n"); ++ } ++ } ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "pre-supportability = 0x%llx\n", pre_support_ability); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "Cur-supportability = 0x%llx\n", dm->support_ability); ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "================================\n"); ++ ++ *_used = used; ++ *_out_len = out_len; ++} ++ ++void phydm_watchdog_lps_32k(struct dm_struct *dm) ++{ ++ PHYDM_DBG(dm, DBG_COMMON_FLOW, "%s ======>\n", __func__); ++ ++ phydm_common_info_self_update(dm); ++ phydm_rssi_monitor_check(dm); ++ phydm_dig_lps_32k(dm); ++ phydm_common_info_self_reset(dm); ++} ++ ++void phydm_watchdog_lps(struct dm_struct *dm) ++{ ++#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE | ODM_IOT)) ++ PHYDM_DBG(dm, DBG_COMMON_FLOW, "%s ======>\n", __func__); ++ ++ phydm_common_info_self_update(dm); ++ phydm_rssi_monitor_check(dm); ++ phydm_basic_dbg_message(dm); ++ phydm_receiver_blocking(dm); ++ phydm_false_alarm_counter_statistics(dm); ++ phydm_dig_by_rssi_lps(dm); ++ #ifdef PHYDM_SUPPORT_CCKPD ++ phydm_cck_pd_th(dm); ++ #endif ++ phydm_adaptivity(dm); ++ #if (DM_ODM_SUPPORT_TYPE & (ODM_CE)) ++ #ifdef CONFIG_PHYDM_ANTENNA_DIVERSITY ++ /*@enable AntDiv in PS mode, request from SD4 Jeff*/ ++ odm_antenna_diversity(dm); ++ #endif ++ #endif ++ phydm_common_info_self_reset(dm); ++#endif ++} ++ ++void phydm_watchdog_mp(struct dm_struct *dm) ++{ ++} ++ ++void phydm_pause_dm_watchdog(void *dm_void, enum phydm_pause_type pause_type) ++{ ++ struct dm_struct *dm = (struct dm_struct *)dm_void; ++ ++ if (pause_type == PHYDM_PAUSE) { ++ dm->disable_phydm_watchdog = 1; ++ PHYDM_DBG(dm, ODM_COMP_API, "PHYDM Stop\n"); ++ } else { ++ dm->disable_phydm_watchdog = 0; ++ PHYDM_DBG(dm, ODM_COMP_API, "PHYDM Start\n"); ++ } ++} ++ ++u8 phydm_pause_func(void *dm_void, enum phydm_func_idx pause_func, ++ enum phydm_pause_type pause_type, ++ enum phydm_pause_level pause_lv, u8 val_lehgth, ++ u32 *val_buf) ++{ ++ struct dm_struct *dm = (struct dm_struct *)dm_void; ++ struct phydm_func_poiner *func_t = &dm->phydm_func_handler; ++ s8 *pause_lv_pre = &dm->s8_dummy; ++ u32 *bkp_val = &dm->u32_dummy; ++ u32 ori_val[5] = {0}; ++ u64 pause_func_bitmap = (u64)BIT(pause_func); ++ u8 i = 0; ++ u8 en_2rcca = 0; ++ u8 en_bw40m = 0; ++ u8 pause_result = PAUSE_FAIL; ++ ++ PHYDM_DBG(dm, ODM_COMP_API, "\n"); ++ PHYDM_DBG(dm, ODM_COMP_API, "[%s][%s] LV=%d, Len=%d\n", __func__, ++ ((pause_type == PHYDM_PAUSE) ? "Pause" : ++ ((pause_type == PHYDM_RESUME) ? "Resume" : "Pause no_set")), ++ pause_lv, val_lehgth); ++ ++ if (pause_lv >= PHYDM_PAUSE_MAX_NUM) { ++ PHYDM_DBG(dm, ODM_COMP_API, "[WARNING]Wrong LV=%d\n", pause_lv); ++ return PAUSE_FAIL; ++ } ++ ++ if (pause_func == F00_DIG) { ++ PHYDM_DBG(dm, ODM_COMP_API, "[DIG]\n"); ++ ++ if (val_lehgth != 1) { ++ PHYDM_DBG(dm, ODM_COMP_API, "[WARNING] length != 1\n"); ++ return PAUSE_FAIL; ++ } ++ ++ ori_val[0] = (u32)(dm->dm_dig_table.cur_ig_value); ++ pause_lv_pre = &dm->pause_lv_table.lv_dig; ++ bkp_val = (u32 *)(&dm->dm_dig_table.rvrt_val); ++ /*@function pointer hook*/ ++ func_t->pause_phydm_handler = phydm_set_dig_val; ++ ++#ifdef PHYDM_SUPPORT_CCKPD ++ } else if (pause_func == F05_CCK_PD) { ++ PHYDM_DBG(dm, ODM_COMP_API, "[CCK_PD]\n"); ++ ++ if (val_lehgth != 1) { ++ PHYDM_DBG(dm, ODM_COMP_API, "[WARNING] length != 1\n"); ++ return PAUSE_FAIL; ++ } ++ ++ ori_val[0] = (u32)dm->dm_cckpd_table.cck_pd_lv; ++ pause_lv_pre = &dm->pause_lv_table.lv_cckpd; ++ bkp_val = (u32 *)(&dm->dm_cckpd_table.rvrt_val); ++ /*@function pointer hook*/ ++ func_t->pause_phydm_handler = phydm_set_cckpd_val; ++#endif ++ ++#ifdef CONFIG_PHYDM_ANTENNA_DIVERSITY ++ } else if (pause_func == F06_ANT_DIV) { ++ PHYDM_DBG(dm, ODM_COMP_API, "[AntDiv]\n"); ++ ++ if (val_lehgth != 1) { ++ PHYDM_DBG(dm, ODM_COMP_API, "[WARNING] length != 1\n"); ++ return PAUSE_FAIL; ++ } ++ /*@default antenna*/ ++ ori_val[0] = (u32)(dm->dm_fat_table.rx_idle_ant); ++ pause_lv_pre = &dm->pause_lv_table.lv_antdiv; ++ bkp_val = (u32 *)(&dm->dm_fat_table.rvrt_val); ++ /*@function pointer hook*/ ++ func_t->pause_phydm_handler = phydm_set_antdiv_val; ++ ++#endif ++#ifdef PHYDM_SUPPORT_ADAPTIVITY ++ } else if (pause_func == F13_ADPTVTY) { ++ PHYDM_DBG(dm, ODM_COMP_API, "[Adaptivity]\n"); ++ ++ if (val_lehgth != 2) { ++ PHYDM_DBG(dm, ODM_COMP_API, "[WARNING] length != 2\n"); ++ return PAUSE_FAIL; ++ } ++ ++ ori_val[0] = (u32)(dm->adaptivity.th_l2h); /*th_l2h*/ ++ ori_val[1] = (u32)(dm->adaptivity.th_h2l); /*th_h2l*/ ++ pause_lv_pre = &dm->pause_lv_table.lv_adapt; ++ bkp_val = (u32 *)(&dm->adaptivity.rvrt_val); ++ /*@function pointer hook*/ ++ func_t->pause_phydm_handler = phydm_set_edcca_val; ++ ++#endif ++#ifdef CONFIG_ADAPTIVE_SOML ++ } else if (pause_func == F17_ADPTV_SOML) { ++ PHYDM_DBG(dm, ODM_COMP_API, "[AD-SOML]\n"); ++ ++ if (val_lehgth != 1) { ++ PHYDM_DBG(dm, ODM_COMP_API, "[WARNING] length != 1\n"); ++ return PAUSE_FAIL; ++ } ++ /*SOML_ON/OFF*/ ++ ori_val[0] = (u32)(dm->dm_soml_table.soml_on_off); ++ ++ pause_lv_pre = &dm->pause_lv_table.lv_adsl; ++ bkp_val = (u32 *)(&dm->dm_soml_table.rvrt_val); ++ /*@function pointer hook*/ ++ func_t->pause_phydm_handler = phydm_set_adsl_val; ++ ++#endif ++ } else { ++ PHYDM_DBG(dm, ODM_COMP_API, "[WARNING] error func idx\n"); ++ return PAUSE_FAIL; ++ } ++ ++ PHYDM_DBG(dm, ODM_COMP_API, "Pause_LV{new , pre} = {%d ,%d}\n", ++ pause_lv, *pause_lv_pre); ++ ++ if (pause_type == PHYDM_PAUSE || pause_type == PHYDM_PAUSE_NO_SET) { ++ if (pause_lv <= *pause_lv_pre) { ++ PHYDM_DBG(dm, ODM_COMP_API, ++ "[PAUSE FAIL] Pre_LV >= Curr_LV\n"); ++ return PAUSE_FAIL; ++ } ++ ++ if (!(dm->pause_ability & pause_func_bitmap)) { ++ for (i = 0; i < val_lehgth; i++) ++ bkp_val[i] = ori_val[i]; ++ } ++ ++ dm->pause_ability |= pause_func_bitmap; ++ PHYDM_DBG(dm, ODM_COMP_API, "pause_ability=0x%llx\n", ++ dm->pause_ability); ++ ++ if (pause_type == PHYDM_PAUSE) { ++ for (i = 0; i < val_lehgth; i++) ++ PHYDM_DBG(dm, ODM_COMP_API, ++ "[PAUSE SUCCESS] val_idx[%d]{New, Ori}={0x%x, 0x%x}\n", ++ i, val_buf[i], bkp_val[i]); ++ func_t->pause_phydm_handler(dm, val_buf, val_lehgth); ++ } else { ++ for (i = 0; i < val_lehgth; i++) ++ PHYDM_DBG(dm, ODM_COMP_API, ++ "[PAUSE NO Set: SUCCESS] val_idx[%d]{Ori}={0x%x}\n", ++ i, bkp_val[i]); ++ } ++ ++ *pause_lv_pre = pause_lv; ++ pause_result = PAUSE_SUCCESS; ++ ++ } else if (pause_type == PHYDM_RESUME) { ++ if ((dm->pause_ability & pause_func_bitmap) == 0) { ++ PHYDM_DBG(dm, ODM_COMP_API, ++ "[RESUME] No Need to Revert\n"); ++ return PAUSE_SUCCESS; ++ } ++ ++ dm->pause_ability &= ~pause_func_bitmap; ++ PHYDM_DBG(dm, ODM_COMP_API, "pause_ability=0x%llx\n", ++ dm->pause_ability); ++ ++ *pause_lv_pre = PHYDM_PAUSE_RELEASE; ++ ++ for (i = 0; i < val_lehgth; i++) { ++ PHYDM_DBG(dm, ODM_COMP_API, ++ "[RESUME] val_idx[%d]={0x%x}\n", i, ++ bkp_val[i]); ++ } ++ ++ func_t->pause_phydm_handler(dm, bkp_val, val_lehgth); ++ ++ pause_result = PAUSE_SUCCESS; ++ } else { ++ PHYDM_DBG(dm, ODM_COMP_API, "[WARNING] error pause_type\n"); ++ pause_result = PAUSE_FAIL; ++ } ++ return pause_result; ++} ++ ++void phydm_pause_func_console(void *dm_void, char input[][16], u32 *_used, ++ char *output, u32 *_out_len) ++{ ++ struct dm_struct *dm = (struct dm_struct *)dm_void; ++ char help[] = "-h"; ++ u32 var1[10] = {0}; ++ u32 used = *_used; ++ u32 out_len = *_out_len; ++ u32 i; ++ u8 length = 0; ++ u32 buf[5] = {0}; ++ u8 set_result = 0; ++ enum phydm_func_idx func = 0; ++ enum phydm_pause_type type = 0; ++ enum phydm_pause_level lv = 0; ++ ++ if ((strcmp(input[1], help) == 0)) { ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "{Func} {1:pause,2:pause no set 3:Resume} {lv:0~3} Val[5:0]\n"); ++ ++ goto out; ++ } ++ ++ for (i = 0; i < 10; i++) { ++ if (input[i + 1]) ++ PHYDM_SSCANF(input[i + 1], DCMD_HEX, &var1[i]); ++ } ++ ++ func = (enum phydm_func_idx)var1[0]; ++ type = (enum phydm_pause_type)var1[1]; ++ lv = (enum phydm_pause_level)var1[2]; ++ ++ for (i = 0; i < 5; i++) ++ buf[i] = var1[3 + i]; ++ ++ if (func == F00_DIG) { ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "[DIG]\n"); ++ length = 1; ++ ++ } else if (func == F05_CCK_PD) { ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "[CCK_PD]\n"); ++ length = 1; ++ } else if (func == F06_ANT_DIV) { ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "[Ant_Div]\n"); ++ length = 1; ++ } else if (func == F13_ADPTVTY) { ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "[Adaptivity]\n"); ++ length = 2; ++ } else if (func == F17_ADPTV_SOML) { ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "[ADSL]\n"); ++ length = 1; ++ } else { ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "[Set Function Error]\n"); ++ length = 0; ++ } ++ ++ if (length != 0) { ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "{%s, lv=%d} val = %d, %d}\n", ++ ((type == PHYDM_PAUSE) ? "Pause" : ++ ((type == PHYDM_RESUME) ? "Resume" : "Pause no_set")), ++ lv, var1[3], var1[4]); ++ ++ set_result = phydm_pause_func(dm, func, type, lv, length, buf); ++ } ++ ++ PDM_SNPF(out_len, used, output + used, out_len - used, ++ "set_result = %d\n", set_result); ++ ++out: ++ *_used = used; ++ *_out_len = out_len; ++} ++ ++u8 phydm_stop_dm_watchdog_check(void *dm_void) ++{ ++ struct dm_struct *dm = (struct dm_struct *)dm_void; ++ ++ if (dm->disable_phydm_watchdog == 1) { ++ PHYDM_DBG(dm, DBG_COMMON_FLOW, "Disable phydm\n"); ++ return true; ++ } else { ++ return false; ++ } ++} ++ ++void phydm_watchdog(struct dm_struct *dm) ++{ ++ PHYDM_DBG(dm, DBG_COMMON_FLOW, "%s ======>\n", __func__); ++ ++ phydm_common_info_self_update(dm); ++ phydm_phy_info_update(dm); ++ phydm_rssi_monitor_check(dm); ++ phydm_basic_dbg_message(dm); ++ phydm_dm_summary(dm, FIRST_MACID); ++#ifdef PHYDM_AUTO_DEGBUG ++ phydm_auto_dbg_engine(dm); ++#endif ++ phydm_receiver_blocking(dm); ++ ++ if (phydm_stop_dm_watchdog_check(dm) == true) ++ return; ++ ++ phydm_hw_setting(dm); ++ ++ #ifdef PHYDM_TDMA_DIG_SUPPORT ++ if (dm->original_dig_restore == 0) ++ phydm_tdma_dig_timer_check(dm); ++ else ++ #endif ++ { ++ phydm_false_alarm_counter_statistics(dm); ++ phydm_noisy_detection(dm); ++ phydm_dig(dm); ++ #ifdef PHYDM_SUPPORT_CCKPD ++ phydm_cck_pd_th(dm); ++ #endif ++ } ++ ++#ifdef PHYDM_POWER_TRAINING_SUPPORT ++ phydm_update_power_training_state(dm); ++#endif ++ phydm_adaptivity(dm); ++ phydm_ra_info_watchdog(dm); ++#ifdef CONFIG_PATH_DIVERSITY ++ phydm_tx_path_diversity(dm); ++#endif ++ phydm_cfo_tracking(dm); ++#ifdef CONFIG_DYNAMIC_TX_TWR ++ phydm_dynamic_tx_power(dm); ++#endif ++#ifdef CONFIG_PHYDM_ANTENNA_DIVERSITY ++ odm_antenna_diversity(dm); ++#endif ++#ifdef CONFIG_ADAPTIVE_SOML ++ phydm_adaptive_soml(dm); ++#endif ++ ++#ifdef PHYDM_BEAMFORMING_VERSION1 ++ phydm_beamforming_watchdog(dm); ++#endif ++ ++ halrf_watchdog(dm); ++#ifdef PHYDM_PRIMARY_CCA ++ phydm_primary_cca(dm); ++#endif ++#if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ odm_dtc(dm); ++#endif ++ ++ phydm_env_mntr_watchdog(dm); ++ ++#ifdef PHYDM_LNA_SAT_CHK_SUPPORT ++ phydm_lna_sat_chk_watchdog(dm); ++#endif ++#ifdef CONFIG_MCC_DM ++ #if (RTL8822B_SUPPORT == 1) ++ phydm_mcc_switch(dm); ++ #endif ++#endif ++ phydm_common_info_self_reset(dm); ++} ++ ++/*@ ++ * Init /.. Fixed HW value. Only init time. ++ */ ++void odm_cmn_info_init(struct dm_struct *dm, enum odm_cmninfo cmn_info, ++ u64 value) ++{ ++ /* This section is used for init value */ ++ switch (cmn_info) { ++ /* @Fixed ODM value. */ ++ case ODM_CMNINFO_ABILITY: ++ dm->support_ability = (u64)value; ++ break; ++ ++ case ODM_CMNINFO_RF_TYPE: ++ dm->rf_type = (u8)value; ++ break; ++ ++ case ODM_CMNINFO_PLATFORM: ++ dm->support_platform = (u8)value; ++ break; ++ ++ case ODM_CMNINFO_INTERFACE: ++ dm->support_interface = (u8)value; ++ break; ++ ++ case ODM_CMNINFO_IC_TYPE: ++ dm->support_ic_type = (u32)value; ++ break; ++ ++ case ODM_CMNINFO_CUT_VER: ++ dm->cut_version = (u8)value; ++ break; ++ ++ case ODM_CMNINFO_FAB_VER: ++ dm->fab_version = (u8)value; ++ break; ++ case ODM_CMNINFO_FW_VER: ++ dm->fw_version = (u8)value; ++ break; ++ case ODM_CMNINFO_FW_SUB_VER: ++ dm->fw_sub_version = (u8)value; ++ break; ++ case ODM_CMNINFO_RFE_TYPE: ++#if (RTL8821C_SUPPORT == 1) ++ if (dm->support_ic_type & ODM_RTL8821C) ++ dm->rfe_type_expand = (u8)value; ++ else ++#endif ++ dm->rfe_type = (u8)value; ++ phydm_init_hw_info_by_rfe(dm); ++ break; ++ ++ case ODM_CMNINFO_RF_ANTENNA_TYPE: ++ dm->ant_div_type = (u8)value; ++ break; ++ ++ case ODM_CMNINFO_WITH_EXT_ANTENNA_SWITCH: ++ dm->with_extenal_ant_switch = (u8)value; ++ break; ++ ++#ifdef CONFIG_PHYDM_ANTENNA_DIVERSITY ++ case ODM_CMNINFO_BE_FIX_TX_ANT: ++ dm->dm_fat_table.b_fix_tx_ant = (u8)value; ++ break; ++#endif ++ ++ case ODM_CMNINFO_BOARD_TYPE: ++ if (!dm->is_init_hw_info_by_rfe) ++ dm->board_type = (u8)value; ++ break; ++ ++ case ODM_CMNINFO_PACKAGE_TYPE: ++ if (!dm->is_init_hw_info_by_rfe) ++ dm->package_type = (u8)value; ++ break; ++ ++ case ODM_CMNINFO_EXT_LNA: ++ if (!dm->is_init_hw_info_by_rfe) ++ dm->ext_lna = (u8)value; ++ break; ++ ++ case ODM_CMNINFO_5G_EXT_LNA: ++ if (!dm->is_init_hw_info_by_rfe) ++ dm->ext_lna_5g = (u8)value; ++ break; ++ ++ case ODM_CMNINFO_EXT_PA: ++ if (!dm->is_init_hw_info_by_rfe) ++ dm->ext_pa = (u8)value; ++ break; ++ ++ case ODM_CMNINFO_5G_EXT_PA: ++ if (!dm->is_init_hw_info_by_rfe) ++ dm->ext_pa_5g = (u8)value; ++ break; ++ ++ case ODM_CMNINFO_GPA: ++ if (!dm->is_init_hw_info_by_rfe) ++ dm->type_gpa = (u16)value; ++ break; ++ ++ case ODM_CMNINFO_APA: ++ if (!dm->is_init_hw_info_by_rfe) ++ dm->type_apa = (u16)value; ++ break; ++ ++ case ODM_CMNINFO_GLNA: ++ if (!dm->is_init_hw_info_by_rfe) ++ dm->type_glna = (u16)value; ++ break; ++ ++ case ODM_CMNINFO_ALNA: ++ if (!dm->is_init_hw_info_by_rfe) ++ dm->type_alna = (u16)value; ++ break; ++ ++ case ODM_CMNINFO_EXT_TRSW: ++ if (!dm->is_init_hw_info_by_rfe) ++ dm->ext_trsw = (u8)value; ++ break; ++ case ODM_CMNINFO_EXT_LNA_GAIN: ++ dm->ext_lna_gain = (u8)value; ++ break; ++ case ODM_CMNINFO_PATCH_ID: ++ dm->iot_table.win_patch_id = (u8)value; ++ break; ++ case ODM_CMNINFO_BINHCT_TEST: ++ dm->is_in_hct_test = (boolean)value; ++ break; ++ case ODM_CMNINFO_BWIFI_TEST: ++ dm->wifi_test = (u8)value; ++ break; ++ case ODM_CMNINFO_SMART_CONCURRENT: ++ dm->is_dual_mac_smart_concurrent = (boolean)value; ++ break; ++#if (DM_ODM_SUPPORT_TYPE & (ODM_AP)) ++ case ODM_CMNINFO_CONFIG_BB_RF: ++ dm->config_bbrf = (boolean)value; ++ break; ++#endif ++ case ODM_CMNINFO_IQKPAOFF: ++ dm->rf_calibrate_info.is_iqk_pa_off = (boolean)value; ++ break; ++ case ODM_CMNINFO_REGRFKFREEENABLE: ++ dm->rf_calibrate_info.reg_rf_kfree_enable = (u8)value; ++ break; ++ case ODM_CMNINFO_RFKFREEENABLE: ++ dm->rf_calibrate_info.rf_kfree_enable = (u8)value; ++ break; ++ case ODM_CMNINFO_NORMAL_RX_PATH_CHANGE: ++ dm->normal_rx_path = (u8)value; ++ break; ++ case ODM_CMNINFO_EFUSE0X3D8: ++ dm->efuse0x3d8 = (u8)value; ++ break; ++ case ODM_CMNINFO_EFUSE0X3D7: ++ dm->efuse0x3d7 = (u8)value; ++ break; ++ case ODM_CMNINFO_ADVANCE_OTA: ++ dm->p_advance_ota = (u8)value; ++ break; ++ ++#ifdef CONFIG_PHYDM_DFS_MASTER ++ case ODM_CMNINFO_DFS_REGION_DOMAIN: ++ dm->dfs_region_domain = (u8)value; ++ break; ++#endif ++ case ODM_CMNINFO_SOFT_AP_SPECIAL_SETTING: ++ dm->soft_ap_special_setting = (u32)value; ++ break; ++ ++ case ODM_CMNINFO_X_CAP_SETTING: ++ dm->dm_cfo_track.crystal_cap_default = (u8)value; ++ break; ++ ++ case ODM_CMNINFO_DPK_EN: ++ /*@dm->dpk_en = (u1Byte)value;*/ ++ halrf_cmn_info_set(dm, HALRF_CMNINFO_DPK_EN, (u64)value); ++ break; ++ ++ case ODM_CMNINFO_HP_HWID: ++ dm->hp_hw_id = (boolean)value; ++ break; ++ default: ++ break; ++ } ++} ++ ++void odm_cmn_info_hook(struct dm_struct *dm, enum odm_cmninfo cmn_info, ++ void *value) ++{ ++ /* @Hook call by reference pointer. */ ++ switch (cmn_info) { ++ /* @Dynamic call by reference pointer. */ ++ case ODM_CMNINFO_TX_UNI: ++ dm->num_tx_bytes_unicast = (u64 *)value; ++ break; ++ ++ case ODM_CMNINFO_RX_UNI: ++ dm->num_rx_bytes_unicast = (u64 *)value; ++ break; ++ ++ case ODM_CMNINFO_BAND: ++ dm->band_type = (u8 *)value; ++ break; ++ ++ case ODM_CMNINFO_SEC_CHNL_OFFSET: ++ dm->sec_ch_offset = (u8 *)value; ++ break; ++ ++ case ODM_CMNINFO_SEC_MODE: ++ dm->security = (u8 *)value; ++ break; ++ ++ case ODM_CMNINFO_BW: ++ dm->band_width = (u8 *)value; ++ break; ++ ++ case ODM_CMNINFO_CHNL: ++ dm->channel = (u8 *)value; ++ break; ++ ++ case ODM_CMNINFO_SCAN: ++ dm->is_scan_in_process = (boolean *)value; ++ break; ++ ++ case ODM_CMNINFO_POWER_SAVING: ++ dm->is_power_saving = (boolean *)value; ++ break; ++ ++ case ODM_CMNINFO_TDMA: ++ dm->is_tdma = (boolean *)value; ++ break; ++ ++ case ODM_CMNINFO_ONE_PATH_CCA: ++ dm->one_path_cca = (u8 *)value; ++ break; ++ ++ case ODM_CMNINFO_DRV_STOP: ++ dm->is_driver_stopped = (boolean *)value; ++ break; ++ case ODM_CMNINFO_INIT_ON: ++ dm->pinit_adpt_in_progress = (boolean *)value; ++ break; ++ ++ case ODM_CMNINFO_ANT_TEST: ++ dm->antenna_test = (u8 *)value; ++ break; ++ ++ case ODM_CMNINFO_NET_CLOSED: ++ dm->is_net_closed = (boolean *)value; ++ break; ++ ++ case ODM_CMNINFO_FORCED_RATE: ++ dm->forced_data_rate = (u16 *)value; ++ break; ++ case ODM_CMNINFO_ANT_DIV: ++ dm->enable_antdiv = (u8 *)value; ++ break; ++ case ODM_CMNINFO_PATH_DIV: ++ dm->enable_pathdiv = (u8 *)value; ++ break; ++ case ODM_CMNINFO_ADAPTIVE_SOML: ++ dm->en_adap_soml = (u8 *)value; ++ break; ++ case ODM_CMNINFO_ADAPTIVITY: ++ dm->enable_adaptivity = (u8 *)value; ++ break; ++ ++ case ODM_CMNINFO_P2P_LINK: ++ dm->dm_dig_table.is_p2p_in_process = (u8 *)value; ++ break; ++ ++ case ODM_CMNINFO_IS1ANTENNA: ++ dm->is_1_antenna = (boolean *)value; ++ break; ++ ++ case ODM_CMNINFO_RFDEFAULTPATH: ++ dm->rf_default_path = (u8 *)value; ++ break; ++ ++ case ODM_CMNINFO_FCS_MODE: ++ dm->is_fcs_mode_enable = (boolean *)value; ++ break; ++ ++ case ODM_CMNINFO_HUBUSBMODE: ++ dm->hub_usb_mode = (u8 *)value; ++ break; ++ case ODM_CMNINFO_FWDWRSVDPAGEINPROGRESS: ++ dm->is_fw_dw_rsvd_page_in_progress = (boolean *)value; ++ break; ++ case ODM_CMNINFO_TX_TP: ++ dm->current_tx_tp = (u32 *)value; ++ break; ++ case ODM_CMNINFO_RX_TP: ++ dm->current_rx_tp = (u32 *)value; ++ break; ++ case ODM_CMNINFO_SOUNDING_SEQ: ++ dm->sounding_seq = (u8 *)value; ++ break; ++#ifdef CONFIG_PHYDM_DFS_MASTER ++ case ODM_CMNINFO_DFS_MASTER_ENABLE: ++ dm->dfs_master_enabled = (u8 *)value; ++ break; ++#endif ++ ++#ifdef CONFIG_PHYDM_ANTENNA_DIVERSITY ++ case ODM_CMNINFO_FORCE_TX_ANT_BY_TXDESC: ++ dm->dm_fat_table.p_force_tx_by_desc = (u8 *)value; ++ break; ++ case ODM_CMNINFO_SET_S0S1_DEFAULT_ANTENNA: ++ dm->dm_fat_table.p_default_s0_s1 = (u8 *)value; ++ break; ++ case ODM_CMNINFO_BF_ANTDIV_DECISION: ++ dm->dm_fat_table.is_no_csi_feedback = (boolean *)value; ++ break; ++#endif ++ ++ case ODM_CMNINFO_SOFT_AP_MODE: ++ dm->soft_ap_mode = (u32 *)value; ++ break; ++ case ODM_CMNINFO_MP_MODE: ++ dm->mp_mode = (u8 *)value; ++ break; ++ case ODM_CMNINFO_INTERRUPT_MASK: ++ dm->interrupt_mask = (u32 *)value; ++ break; ++ case ODM_CMNINFO_BB_OPERATION_MODE: ++ dm->bb_op_mode = (u8 *)value; ++ break; ++ default: ++ /*do nothing*/ ++ break; ++ } ++} ++ ++/*@ ++ * Update band/CHannel/.. The values are dynamic but non-per-packet. ++ */ ++void odm_cmn_info_update(struct dm_struct *dm, u32 cmn_info, u64 value) ++{ ++ /* This init variable may be changed in run time. */ ++ switch (cmn_info) { ++ case ODM_CMNINFO_LINK_IN_PROGRESS: ++ dm->is_link_in_process = (boolean)value; ++ break; ++ ++ case ODM_CMNINFO_ABILITY: ++ dm->support_ability = (u64)value; ++ break; ++ ++ case ODM_CMNINFO_RF_TYPE: ++ dm->rf_type = (u8)value; ++ break; ++ ++ case ODM_CMNINFO_WIFI_DIRECT: ++ dm->is_wifi_direct = (boolean)value; ++ break; ++ ++ case ODM_CMNINFO_WIFI_DISPLAY: ++ dm->is_wifi_display = (boolean)value; ++ break; ++ ++ case ODM_CMNINFO_LINK: ++ dm->is_linked = (boolean)value; ++ break; ++ ++ case ODM_CMNINFO_CMW500LINK: ++ dm->iot_table.is_linked_cmw500 = (boolean)value; ++ break; ++ ++ case ODM_CMNINFO_STATION_STATE: ++ dm->bsta_state = (boolean)value; ++ break; ++ ++ case ODM_CMNINFO_RSSI_MIN: ++ dm->rssi_min = (u8)value; ++ break; ++ ++ case ODM_CMNINFO_RSSI_MIN_BY_PATH: ++ dm->rssi_min_by_path = (u8)value; ++ break; ++ ++ case ODM_CMNINFO_DBG_COMP: ++ dm->debug_components = (u64)value; ++ break; ++ ++#ifdef ODM_CONFIG_BT_COEXIST ++ /* The following is for BT HS mode and BT coexist mechanism. */ ++ case ODM_CMNINFO_BT_ENABLED: ++ dm->bt_info_table.is_bt_enabled = (boolean)value; ++ break; ++ ++ case ODM_CMNINFO_BT_HS_CONNECT_PROCESS: ++ dm->bt_info_table.is_bt_connect_process = (boolean)value; ++ break; ++ ++ case ODM_CMNINFO_BT_HS_RSSI: ++ dm->bt_info_table.bt_hs_rssi = (u8)value; ++ break; ++ ++ case ODM_CMNINFO_BT_OPERATION: ++ dm->bt_info_table.is_bt_hs_operation = (boolean)value; ++ break; ++ ++ case ODM_CMNINFO_BT_LIMITED_DIG: ++ dm->bt_info_table.is_bt_limited_dig = (boolean)value; ++ break; ++#endif ++ ++ case ODM_CMNINFO_AP_TOTAL_NUM: ++ dm->ap_total_num = (u8)value; ++ break; ++ ++#ifdef CONFIG_PHYDM_DFS_MASTER ++ case ODM_CMNINFO_DFS_REGION_DOMAIN: ++ dm->dfs_region_domain = (u8)value; ++ break; ++#endif ++ ++ case ODM_CMNINFO_BT_CONTINUOUS_TURN: ++ dm->is_bt_continuous_turn = (boolean)value; ++ break; ++ default: ++ break; ++ } ++} ++ ++u32 phydm_cmn_info_query(struct dm_struct *dm, enum phydm_info_query info_type) ++{ ++ struct phydm_fa_struct *fa_t = &dm->false_alm_cnt; ++ struct phydm_dig_struct *dig_t = &dm->dm_dig_table; ++ struct ccx_info *ccx_info = &dm->dm_ccx_info; ++ ++ switch (info_type) { ++ /*@=== [FA Relative] ===========================================*/ ++ case PHYDM_INFO_FA_OFDM: ++ return fa_t->cnt_ofdm_fail; ++ ++ case PHYDM_INFO_FA_CCK: ++ return fa_t->cnt_cck_fail; ++ ++ case PHYDM_INFO_FA_TOTAL: ++ return fa_t->cnt_all; ++ ++ case PHYDM_INFO_CCA_OFDM: ++ return fa_t->cnt_ofdm_cca; ++ ++ case PHYDM_INFO_CCA_CCK: ++ return fa_t->cnt_cck_cca; ++ ++ case PHYDM_INFO_CCA_ALL: ++ return fa_t->cnt_cca_all; ++ ++ case PHYDM_INFO_CRC32_OK_VHT: ++ return fa_t->cnt_vht_crc32_ok; ++ ++ case PHYDM_INFO_CRC32_OK_HT: ++ return fa_t->cnt_ht_crc32_ok; ++ ++ case PHYDM_INFO_CRC32_OK_LEGACY: ++ return fa_t->cnt_ofdm_crc32_ok; ++ ++ case PHYDM_INFO_CRC32_OK_CCK: ++ return fa_t->cnt_cck_crc32_ok; ++ ++ case PHYDM_INFO_CRC32_ERROR_VHT: ++ return fa_t->cnt_vht_crc32_error; ++ ++ case PHYDM_INFO_CRC32_ERROR_HT: ++ return fa_t->cnt_ht_crc32_error; ++ ++ case PHYDM_INFO_CRC32_ERROR_LEGACY: ++ return fa_t->cnt_ofdm_crc32_error; ++ ++ case PHYDM_INFO_CRC32_ERROR_CCK: ++ return fa_t->cnt_cck_crc32_error; ++ ++ case PHYDM_INFO_EDCCA_FLAG: ++ return fa_t->edcca_flag; ++ ++ case PHYDM_INFO_OFDM_ENABLE: ++ return fa_t->ofdm_block_enable; ++ ++ case PHYDM_INFO_CCK_ENABLE: ++ return fa_t->cck_block_enable; ++ ++ case PHYDM_INFO_DBG_PORT_0: ++ return fa_t->dbg_port0; ++ ++ case PHYDM_INFO_CRC32_OK_HT_AGG: ++ return fa_t->cnt_ht_crc32_ok_agg; ++ ++ case PHYDM_INFO_CRC32_ERROR_HT_AGG: ++ return fa_t->cnt_ht_crc32_error_agg; ++ ++ /*@=== [DIG] ================================================*/ ++ ++ case PHYDM_INFO_CURR_IGI: ++ return dig_t->cur_ig_value; ++ ++ /*@=== [RSSI] ===============================================*/ ++ case PHYDM_INFO_RSSI_MIN: ++ return (u32)dm->rssi_min; ++ ++ case PHYDM_INFO_RSSI_MAX: ++ return (u32)dm->rssi_max; ++ ++ case PHYDM_INFO_CLM_RATIO: ++ return (u32)ccx_info->clm_ratio; ++ case PHYDM_INFO_NHM_RATIO: ++ return (u32)ccx_info->nhm_ratio; ++ default: ++ return 0xffffffff; ++ } ++} ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) ++void odm_init_all_work_items(struct dm_struct *dm) ++{ ++ void *adapter = dm->adapter; ++#if USE_WORKITEM ++ ++#ifdef CONFIG_ADAPTIVE_SOML ++ odm_initialize_work_item(dm, ++ &dm->dm_soml_table.phydm_adaptive_soml_workitem, ++ (RT_WORKITEM_CALL_BACK)phydm_adaptive_soml_workitem_callback, ++ (void *)adapter, ++ "AdaptiveSOMLWorkitem"); ++#endif ++ ++#ifdef ODM_EVM_ENHANCE_ANTDIV ++ odm_initialize_work_item(dm, ++ &dm->phydm_evm_antdiv_workitem, ++ (RT_WORKITEM_CALL_BACK)phydm_evm_antdiv_workitem_callback, ++ (void *)adapter, ++ "EvmAntdivWorkitem"); ++#endif ++ ++#ifdef CONFIG_S0S1_SW_ANTENNA_DIVERSITY ++ odm_initialize_work_item(dm, ++ &dm->dm_swat_table.phydm_sw_antenna_switch_workitem, ++ (RT_WORKITEM_CALL_BACK)odm_sw_antdiv_workitem_callback, ++ (void *)adapter, ++ "AntennaSwitchWorkitem"); ++#endif ++#if (defined(CONFIG_HL_SMART_ANTENNA)) ++ odm_initialize_work_item(dm, ++ &dm->dm_sat_table.hl_smart_antenna_workitem, ++ (RT_WORKITEM_CALL_BACK)phydm_beam_switch_workitem_callback, ++ (void *)adapter, ++ "hl_smart_ant_workitem"); ++ ++ odm_initialize_work_item(dm, ++ &dm->dm_sat_table.hl_smart_antenna_decision_workitem, ++ (RT_WORKITEM_CALL_BACK)phydm_beam_decision_workitem_callback, ++ (void *)adapter, ++ "hl_smart_ant_decision_workitem"); ++#endif ++ ++ odm_initialize_work_item( ++ dm, ++ &dm->ra_rpt_workitem, ++ (RT_WORKITEM_CALL_BACK)halrf_update_init_rate_work_item_callback, ++ (void *)adapter, ++ "ra_rpt_workitem"); ++ ++#if (defined(CONFIG_5G_CG_SMART_ANT_DIVERSITY)) || (defined(CONFIG_2G_CG_SMART_ANT_DIVERSITY)) ++ odm_initialize_work_item( ++ dm, ++ &dm->fast_ant_training_workitem, ++ (RT_WORKITEM_CALL_BACK)odm_fast_ant_training_work_item_callback, ++ (void *)adapter, ++ "fast_ant_training_workitem"); ++#endif ++ ++#endif /*#if USE_WORKITEM*/ ++ ++#ifdef PHYDM_BEAMFORMING_SUPPORT ++ odm_initialize_work_item( ++ dm, ++ &dm->beamforming_info.txbf_info.txbf_enter_work_item, ++ (RT_WORKITEM_CALL_BACK)hal_com_txbf_enter_work_item_callback, ++ (void *)adapter, ++ "txbf_enter_work_item"); ++ ++ odm_initialize_work_item( ++ dm, ++ &dm->beamforming_info.txbf_info.txbf_leave_work_item, ++ (RT_WORKITEM_CALL_BACK)hal_com_txbf_leave_work_item_callback, ++ (void *)adapter, ++ "txbf_leave_work_item"); ++ ++ odm_initialize_work_item( ++ dm, ++ &dm->beamforming_info.txbf_info.txbf_fw_ndpa_work_item, ++ (RT_WORKITEM_CALL_BACK)hal_com_txbf_fw_ndpa_work_item_callback, ++ (void *)adapter, ++ "txbf_fw_ndpa_work_item"); ++ ++ odm_initialize_work_item( ++ dm, ++ &dm->beamforming_info.txbf_info.txbf_clk_work_item, ++ (RT_WORKITEM_CALL_BACK)hal_com_txbf_clk_work_item_callback, ++ (void *)adapter, ++ "txbf_clk_work_item"); ++ ++ odm_initialize_work_item( ++ dm, ++ &dm->beamforming_info.txbf_info.txbf_rate_work_item, ++ (RT_WORKITEM_CALL_BACK)hal_com_txbf_rate_work_item_callback, ++ (void *)adapter, ++ "txbf_rate_work_item"); ++ ++ odm_initialize_work_item( ++ dm, ++ &dm->beamforming_info.txbf_info.txbf_status_work_item, ++ (RT_WORKITEM_CALL_BACK)hal_com_txbf_status_work_item_callback, ++ (void *)adapter, ++ "txbf_status_work_item"); ++ ++ odm_initialize_work_item( ++ dm, ++ &dm->beamforming_info.txbf_info.txbf_reset_tx_path_work_item, ++ (RT_WORKITEM_CALL_BACK)hal_com_txbf_reset_tx_path_work_item_callback, ++ (void *)adapter, ++ "txbf_reset_tx_path_work_item"); ++ ++ odm_initialize_work_item( ++ dm, ++ &dm->beamforming_info.txbf_info.txbf_get_tx_rate_work_item, ++ (RT_WORKITEM_CALL_BACK)hal_com_txbf_get_tx_rate_work_item_callback, ++ (void *)adapter, ++ "txbf_get_tx_rate_work_item"); ++#endif ++ ++#if (PHYDM_LA_MODE_SUPPORT == 1) ++ odm_initialize_work_item( ++ dm, ++ &dm->adcsmp.adc_smp_work_item, ++ (RT_WORKITEM_CALL_BACK)adc_smp_work_item_callback, ++ (void *)adapter, ++ "adc_smp_work_item"); ++ ++ odm_initialize_work_item( ++ dm, ++ &dm->adcsmp.adc_smp_work_item_1, ++ (RT_WORKITEM_CALL_BACK)adc_smp_work_item_callback, ++ (void *)adapter, ++ "adc_smp_work_item_1"); ++#endif ++} ++ ++void odm_free_all_work_items(struct dm_struct *dm) ++{ ++#if USE_WORKITEM ++ ++#ifdef CONFIG_S0S1_SW_ANTENNA_DIVERSITY ++ odm_free_work_item(&dm->dm_swat_table.phydm_sw_antenna_switch_workitem); ++#endif ++ ++#ifdef CONFIG_ADAPTIVE_SOML ++ odm_free_work_item(&dm->dm_soml_table.phydm_adaptive_soml_workitem); ++#endif ++ ++#ifdef ODM_EVM_ENHANCE_ANTDIV ++ odm_free_work_item(&dm->phydm_evm_antdiv_workitem); ++#endif ++ ++#if (defined(CONFIG_HL_SMART_ANTENNA)) ++ odm_free_work_item(&dm->dm_sat_table.hl_smart_antenna_workitem); ++ odm_free_work_item(&dm->dm_sat_table.hl_smart_antenna_decision_workitem); ++#endif ++ ++#if (defined(CONFIG_5G_CG_SMART_ANT_DIVERSITY)) || (defined(CONFIG_2G_CG_SMART_ANT_DIVERSITY)) ++ odm_free_work_item(&dm->fast_ant_training_workitem); ++#endif ++ odm_free_work_item(&dm->ra_rpt_workitem); ++/*odm_free_work_item((&dm->sbdcnt_workitem));*/ ++#endif ++ ++#ifdef PHYDM_BEAMFORMING_SUPPORT ++ odm_free_work_item((&dm->beamforming_info.txbf_info.txbf_enter_work_item)); ++ odm_free_work_item((&dm->beamforming_info.txbf_info.txbf_leave_work_item)); ++ odm_free_work_item((&dm->beamforming_info.txbf_info.txbf_fw_ndpa_work_item)); ++ odm_free_work_item((&dm->beamforming_info.txbf_info.txbf_clk_work_item)); ++ odm_free_work_item((&dm->beamforming_info.txbf_info.txbf_rate_work_item)); ++ odm_free_work_item((&dm->beamforming_info.txbf_info.txbf_status_work_item)); ++ odm_free_work_item((&dm->beamforming_info.txbf_info.txbf_reset_tx_path_work_item)); ++ odm_free_work_item((&dm->beamforming_info.txbf_info.txbf_get_tx_rate_work_item)); ++#endif ++ ++#if (PHYDM_LA_MODE_SUPPORT == 1) ++ odm_free_work_item((&dm->adcsmp.adc_smp_work_item)); ++ odm_free_work_item((&dm->adcsmp.adc_smp_work_item_1)); ++#endif ++} ++#endif /*#if (DM_ODM_SUPPORT_TYPE == ODM_WIN)*/ ++ ++void odm_init_all_timers(struct dm_struct *dm) ++{ ++#if (defined(CONFIG_PHYDM_ANTENNA_DIVERSITY)) ++ odm_ant_div_timers(dm, INIT_ANTDIV_TIMMER); ++#endif ++#if (defined(PHYDM_TDMA_DIG_SUPPORT)) ++#ifdef IS_USE_NEW_TDMA ++ phydm_tdma_dig_timers(dm, INIT_TDMA_DIG_TIMMER); ++#endif ++#endif ++#ifdef CONFIG_ADAPTIVE_SOML ++ phydm_adaptive_soml_timers(dm, INIT_SOML_TIMMER); ++#endif ++#ifdef PHYDM_LNA_SAT_CHK_SUPPORT ++#ifdef PHYDM_LNA_SAT_CHK_TYPE1 ++ phydm_lna_sat_chk_timers(dm, INIT_LNA_SAT_CHK_TIMMER); ++#endif ++#endif ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) ++ odm_initialize_timer(dm, &dm->sbdcnt_timer, ++ (void *)phydm_sbd_callback, NULL, "SbdTimer"); ++#ifdef PHYDM_BEAMFORMING_SUPPORT ++ odm_initialize_timer(dm, &dm->beamforming_info.txbf_info.txbf_fw_ndpa_timer, ++ (void *)hal_com_txbf_fw_ndpa_timer_callback, NULL, ++ "txbf_fw_ndpa_timer"); ++#endif ++#endif ++ ++#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE)) ++#ifdef PHYDM_BEAMFORMING_SUPPORT ++ odm_initialize_timer(dm, &dm->beamforming_info.beamforming_timer, ++ (void *)beamforming_sw_timer_callback, NULL, ++ "beamforming_timer"); ++#endif ++#endif ++} ++ ++void odm_cancel_all_timers(struct dm_struct *dm) ++{ ++#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) ++ /* @2012/01/12 MH Temp BSOD fix. We need to find NIC allocate mem fail reason in win7*/ ++ if (dm->adapter == NULL) ++ return; ++#endif ++ ++#if (defined(CONFIG_PHYDM_ANTENNA_DIVERSITY)) ++ odm_ant_div_timers(dm, CANCEL_ANTDIV_TIMMER); ++#endif ++#ifdef PHYDM_TDMA_DIG_SUPPORT ++#ifdef IS_USE_NEW_TDMA ++ phydm_tdma_dig_timers(dm, CANCEL_TDMA_DIG_TIMMER); ++#endif ++#endif ++#ifdef CONFIG_ADAPTIVE_SOML ++ phydm_adaptive_soml_timers(dm, CANCEL_SOML_TIMMER); ++#endif ++#ifdef PHYDM_LNA_SAT_CHK_SUPPORT ++#ifdef PHYDM_LNA_SAT_CHK_TYPE1 ++ phydm_lna_sat_chk_timers(dm, CANCEL_LNA_SAT_CHK_TIMMER); ++#endif ++#endif ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) ++ odm_cancel_timer(dm, &dm->sbdcnt_timer); ++#ifdef PHYDM_BEAMFORMING_SUPPORT ++ odm_cancel_timer(dm, &dm->beamforming_info.txbf_info.txbf_fw_ndpa_timer); ++#endif ++#endif ++ ++#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE)) ++#ifdef PHYDM_BEAMFORMING_SUPPORT ++ odm_cancel_timer(dm, &dm->beamforming_info.beamforming_timer); ++#endif ++#endif ++} ++ ++void odm_release_all_timers(struct dm_struct *dm) ++{ ++#if (defined(CONFIG_PHYDM_ANTENNA_DIVERSITY)) ++ odm_ant_div_timers(dm, RELEASE_ANTDIV_TIMMER); ++#endif ++#ifdef PHYDM_TDMA_DIG_SUPPORT ++#ifdef IS_USE_NEW_TDMA ++ phydm_tdma_dig_timers(dm, RELEASE_TDMA_DIG_TIMMER); ++#endif ++#endif ++#ifdef CONFIG_ADAPTIVE_SOML ++ phydm_adaptive_soml_timers(dm, RELEASE_SOML_TIMMER); ++#endif ++#ifdef PHYDM_LNA_SAT_CHK_SUPPORT ++#ifdef PHYDM_LNA_SAT_CHK_TYPE1 ++ phydm_lna_sat_chk_timers(dm, RELEASE_LNA_SAT_CHK_TIMMER); ++#endif ++#endif ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) ++ odm_release_timer(dm, &dm->sbdcnt_timer); ++#ifdef PHYDM_BEAMFORMING_SUPPORT ++ odm_release_timer(dm, &dm->beamforming_info.txbf_info.txbf_fw_ndpa_timer); ++#endif ++#endif ++ ++#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE)) ++#ifdef PHYDM_BEAMFORMING_SUPPORT ++ odm_release_timer(dm, &dm->beamforming_info.beamforming_timer); ++#endif ++#endif ++} ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_AP) ++void odm_init_all_threads( ++ struct dm_struct *dm) ++{ ++#ifdef TPT_THREAD ++ k_tpt_task_init(dm->priv); ++#endif ++} ++ ++void odm_stop_all_threads( ++ struct dm_struct *dm) ++{ ++#ifdef TPT_THREAD ++ k_tpt_task_stop(dm->priv); ++#endif ++} ++#endif ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++/* @Justin: According to the current RRSI to adjust Response Frame TX power, ++ * 2012/11/05 ++ */ ++void odm_dtc(struct dm_struct *dm) ++{ ++#ifdef CONFIG_DM_RESP_TXAGC ++/* RSSI higher than this value, start to decade TX power */ ++#define DTC_BASE 35 ++ ++/* RSSI lower than this value, start to increase TX power */ ++#define DTC_DWN_BASE (DTC_BASE - 5) ++ ++ /* RSSI vs TX power step mapping: decade TX power */ ++ static const u8 dtc_table_down[] = { ++ DTC_BASE, ++ (DTC_BASE + 5), ++ (DTC_BASE + 10), ++ (DTC_BASE + 15), ++ (DTC_BASE + 20), ++ (DTC_BASE + 25)}; ++ ++ /* RSSI vs TX power step mapping: increase TX power */ ++ static const u8 dtc_table_up[] = { ++ DTC_DWN_BASE, ++ (DTC_DWN_BASE - 5), ++ (DTC_DWN_BASE - 10), ++ (DTC_DWN_BASE - 15), ++ (DTC_DWN_BASE - 15), ++ (DTC_DWN_BASE - 20), ++ (DTC_DWN_BASE - 20), ++ (DTC_DWN_BASE - 25), ++ (DTC_DWN_BASE - 25), ++ (DTC_DWN_BASE - 30), ++ (DTC_DWN_BASE - 35)}; ++ ++ u8 i; ++ u8 dtc_steps = 0; ++ u8 sign; ++ u8 resp_txagc = 0; ++ ++#if 0 ++ /* @As DIG is disabled, DTC is also disable */ ++ if (!(dm->support_ability & ODM_XXXXXX)) ++ return; ++#endif ++ ++ if (dm->rssi_min > DTC_BASE) { ++ /* need to decade the CTS TX power */ ++ sign = 1; ++ for (i = 0; i < ARRAY_SIZE(dtc_table_down); i++) { ++ if (dtc_table_down[i] >= dm->rssi_min || dtc_steps >= 6) ++ break; ++ else ++ dtc_steps++; ++ } ++ } ++#if 0 ++ else if (dm->rssi_min > DTC_DWN_BASE) { ++ /* needs to increase the CTS TX power */ ++ sign = 0; ++ dtc_steps = 1; ++ for (i = 0; i < ARRAY_SIZE(dtc_table_up); i++) { ++ if (dtc_table_up[i] <= dm->rssi_min || dtc_steps >= 10) ++ break; ++ else ++ dtc_steps++; ++ } ++ } ++#endif ++ else { ++ sign = 0; ++ dtc_steps = 0; ++ } ++ ++ resp_txagc = dtc_steps | (sign << 4); ++ resp_txagc = resp_txagc | (resp_txagc << 5); ++ odm_write_1byte(dm, 0x06d9, resp_txagc); ++ ++ PHYDM_DBG(dm, ODM_COMP_PWR_TRAIN, ++ "%s rssi_min:%u, set RESP_TXAGC to %s %u\n", __func__, ++ dm->rssi_min, sign ? "minus" : "plus", dtc_steps); ++#endif /* @CONFIG_RESP_TXAGC_ADJUST */ ++} ++ ++#endif /* @#if (DM_ODM_SUPPORT_TYPE == ODM_CE) */ ++ ++/*@<20170126, BB-Kevin>8188F D-CUT DC cancellation and 8821C*/ ++void phydm_dc_cancellation(struct dm_struct *dm) ++{ ++#ifdef PHYDM_DC_CANCELLATION ++ u32 offset_i_hex[PHYDM_MAX_RF_PATH] = {0}; ++ u32 offset_q_hex[PHYDM_MAX_RF_PATH] = {0}; ++ u32 reg_value32[PHYDM_MAX_RF_PATH] = {0}; ++ u8 path = RF_PATH_A; ++ u8 set_result; ++ ++ if (!(dm->support_ic_type & ODM_DC_CANCELLATION_SUPPORT)) ++ return; ++ if ((dm->support_ic_type & ODM_RTL8188F) && ++ dm->cut_version < ODM_CUT_D) ++ return; ++ if ((dm->support_ic_type & ODM_RTL8192F) && ++ dm->cut_version == ODM_CUT_A) ++ return; ++ ++ PHYDM_DBG(dm, ODM_COMP_API, "%s ======>\n", __func__); ++ ++ /*@DC_Estimation (only for 2x2 ic now) */ ++ ++ for (path = RF_PATH_A; path < PHYDM_MAX_RF_PATH; path++) { ++ if (path > RF_PATH_A && ++ dm->support_ic_type & (ODM_RTL8821C | ODM_RTL8188F | ++ ODM_RTL8710B | ODM_RTL8721D)) ++ break; ++ else if (path > RF_PATH_B && ++ dm->support_ic_type & (ODM_RTL8822B | ODM_RTL8192F)) ++ break; ++ if (phydm_stop_ic_trx(dm, PHYDM_SET) == PHYDM_SET_FAIL) { ++ PHYDM_DBG(dm, ODM_COMP_API, "STOP_TRX_FAIL\n"); ++ return; ++ } ++ odm_write_dig(dm, 0x7e); ++ /*@Disable LNA*/ ++ if (dm->support_ic_type & ODM_RTL8821C) ++ halrf_rf_lna_setting(dm, HALRF_LNA_DISABLE); ++ /*Turn off 3-wire*/ ++ phydm_stop_3_wire(dm, PHYDM_SET); ++ if (dm->support_ic_type & (ODM_RTL8188F | ODM_RTL8710B)) { ++ /*set debug port to 0x235*/ ++ if (!phydm_set_bb_dbg_port(dm, DBGPORT_PRI_1, 0x235)) { ++ PHYDM_DBG(dm, ODM_COMP_API, ++ "Set Debug port Fail\n"); ++ return; ++ } ++ } else if (dm->support_ic_type & ODM_RTL8721D) { ++ /*set debug port to 0x200*/ ++ if (!phydm_set_bb_dbg_port(dm, DBGPORT_PRI_2, 0x200)) { ++ PHYDM_DBG(dm, ODM_COMP_API, ++ "Set Debug port Fail\n"); ++ return; ++ } ++ } else if (dm->support_ic_type & ODM_RTL8821C) { ++ if (!phydm_set_bb_dbg_port(dm, DBGPORT_PRI_1, 0x200)) { ++ /*set debug port to 0x200*/ ++ PHYDM_DBG(dm, ODM_COMP_API, ++ "Set Debug port Fail\n"); ++ return; ++ } ++ phydm_bb_dbg_port_header_sel(dm, 0x0); ++ } else if (dm->support_ic_type & ODM_RTL8822B) { ++ if (path == RF_PATH_A && ++ !phydm_set_bb_dbg_port(dm, DBGPORT_PRI_1, 0x200)) { ++ /*set debug port to 0x200*/ ++ PHYDM_DBG(dm, ODM_COMP_API, ++ "Set Debug port Fail\n"); ++ return; ++ } ++ if (path == RF_PATH_B && ++ !phydm_set_bb_dbg_port(dm, DBGPORT_PRI_1, 0x202)) { ++ /*set debug port to 0x200*/ ++ PHYDM_DBG(dm, ODM_COMP_API, ++ "Set Debug port Fail\n"); ++ return; ++ } ++ phydm_bb_dbg_port_header_sel(dm, 0x0); ++ } else if (dm->support_ic_type & ODM_RTL8192F) { ++ if (path == RF_PATH_A && ++ !phydm_set_bb_dbg_port(dm, DBGPORT_PRI_1, 0x235)) { ++ /*set debug port to 0x235*/ ++ PHYDM_DBG(dm, ODM_COMP_API, ++ "Set Debug port Fail\n"); ++ return; ++ } ++ if (path == RF_PATH_B && ++ !phydm_set_bb_dbg_port(dm, DBGPORT_PRI_1, 0x23d)) { ++ /*set debug port to 0x23d*/ ++ PHYDM_DBG(dm, ODM_COMP_API, ++ "Set Debug port Fail\n"); ++ return; ++ } ++ } ++ ++ /*@disable CCK DCNF*/ ++ odm_set_bb_reg(dm, R_0xa78, MASKBYTE1, 0x0); ++ ++ PHYDM_DBG(dm, ODM_COMP_API, "DC cancellation Begin!!!\n"); ++ ++ phydm_stop_ck320(dm, true); /*stop ck320*/ ++ ++ /* the same debug port both for path-a and path-b*/ ++ reg_value32[path] = phydm_get_bb_dbg_port_val(dm); ++ ++ phydm_stop_ck320(dm, false); /*start ck320*/ ++ ++ phydm_release_bb_dbg_port(dm); ++ /* @Turn on 3-wire*/ ++ phydm_stop_3_wire(dm, PHYDM_REVERT); ++ /* @Enable LNA*/ ++ if (dm->support_ic_type & ODM_RTL8821C) ++ halrf_rf_lna_setting(dm, HALRF_LNA_ENABLE); ++ ++ odm_write_dig(dm, 0x20); ++ ++ set_result = phydm_stop_ic_trx(dm, PHYDM_REVERT); ++ ++ PHYDM_DBG(dm, ODM_COMP_API, "DC cancellation OK!!!\n"); ++ } ++ ++ /*@DC_Cancellation*/ ++ /*@DC compensation to CCK data path*/ ++ odm_set_bb_reg(dm, R_0xa9c, BIT(20), 0x1); ++ if (dm->support_ic_type & (ODM_RTL8188F | ODM_RTL8710B)) { ++ offset_i_hex[0] = (reg_value32[0] & 0xffc0000) >> 18; ++ offset_q_hex[0] = (reg_value32[0] & 0x3ff00) >> 8; ++ ++ /*@Before filling into registers, ++ *offset should be multiplexed (-1) ++ */ ++ offset_i_hex[0] = (offset_i_hex[0] >= 0x200) ? ++ (0x400 - offset_i_hex[0]) : ++ (0x1ff - offset_i_hex[0]); ++ offset_q_hex[0] = (offset_q_hex[0] >= 0x200) ? ++ (0x400 - offset_q_hex[0]) : ++ (0x1ff - offset_q_hex[0]); ++ ++ odm_set_bb_reg(dm, R_0x950, 0x1ff, offset_i_hex[0]); ++ odm_set_bb_reg(dm, R_0x950, 0x1ff0000, offset_q_hex[0]); ++ } else if (dm->support_ic_type & (ODM_RTL8821C | ODM_RTL8822B)) { ++ /* Path-a */ ++ offset_i_hex[0] = (reg_value32[0] & 0xffc00) >> 10; ++ offset_q_hex[0] = reg_value32[0] & 0x3ff; ++ ++ /*@Before filling into registers, ++ *offset should be multiplexed (-1) ++ */ ++ offset_i_hex[0] = 0x400 - offset_i_hex[0]; ++ offset_q_hex[0] = 0x400 - offset_q_hex[0]; ++ ++ odm_set_bb_reg(dm, R_0xc10, 0x3c000000, ++ (0x3c0 & offset_i_hex[0]) >> 6); ++ odm_set_bb_reg(dm, R_0xc10, 0xfc00, 0x3f & offset_i_hex[0]); ++ odm_set_bb_reg(dm, R_0xc14, 0x3c000000, ++ (0x3c0 & offset_q_hex[0]) >> 6); ++ odm_set_bb_reg(dm, R_0xc14, 0xfc00, 0x3f & offset_q_hex[0]); ++ ++ /* Path-b */ ++ if (dm->rf_type > RF_1T1R) { ++ offset_i_hex[1] = (reg_value32[1] & 0xffc00) >> 10; ++ offset_q_hex[1] = reg_value32[1] & 0x3ff; ++ ++ /*@Before filling into registers, ++ *offset should be multiplexed (-1) ++ */ ++ offset_i_hex[1] = 0x400 - offset_i_hex[1]; ++ offset_q_hex[1] = 0x400 - offset_q_hex[1]; ++ ++ odm_set_bb_reg(dm, R_0xe10, 0x3c000000, ++ (0x3c0 & offset_i_hex[1]) >> 6); ++ odm_set_bb_reg(dm, R_0xe10, 0xfc00, ++ 0x3f & offset_i_hex[1]); ++ odm_set_bb_reg(dm, R_0xe14, 0x3c000000, ++ (0x3c0 & offset_q_hex[1]) >> 6); ++ odm_set_bb_reg(dm, R_0xe14, 0xfc00, ++ 0x3f & offset_q_hex[1]); ++ } ++ } else if (dm->support_ic_type & (ODM_RTL8192F)) { ++ /* Path-a I:df4[27:18],Q:df4[17:8]*/ ++ offset_i_hex[0] = (reg_value32[0] & 0xffc0000) >> 18; ++ offset_q_hex[0] = (reg_value32[0] & 0x3ff00) >> 8; ++ ++ /*@Before filling into registers, ++ *offset should be multiplexed (-1) ++ */ ++ offset_i_hex[0] = (offset_i_hex[0] >= 0x200) ? ++ (0x400 - offset_i_hex[0]) : ++ (0xff - offset_i_hex[0]); ++ offset_q_hex[0] = (offset_q_hex[0] >= 0x200) ? ++ (0x400 - offset_q_hex[0]) : ++ (0xff - offset_q_hex[0]); ++ /*Path-a I:c10[7:0],Q:c10[15:8]*/ ++ odm_set_bb_reg(dm, R_0xc10, 0xff, offset_i_hex[0]); ++ odm_set_bb_reg(dm, R_0xc10, 0xff00, offset_q_hex[0]); ++ ++ /* Path-b */ ++ if (dm->rf_type > RF_1T1R) { ++ /* @I:df4[27:18],Q:df4[17:8]*/ ++ offset_i_hex[1] = (reg_value32[1] & 0xffc0000) >> 18; ++ offset_q_hex[1] = (reg_value32[1] & 0x3ff00) >> 8; ++ ++ /*@Before filling into registers, ++ *offset should be multiplexed (-1) ++ */ ++ offset_i_hex[1] = (offset_i_hex[1] >= 0x200) ? ++ (0x400 - offset_i_hex[1]) : ++ (0xff - offset_i_hex[1]); ++ offset_q_hex[1] = (offset_q_hex[1] >= 0x200) ? ++ (0x400 - offset_q_hex[1]) : ++ (0xff - offset_q_hex[1]); ++ /*Path-b I:c18[7:0],Q:c18[15:8]*/ ++ odm_set_bb_reg(dm, R_0xc18, 0xff, offset_i_hex[1]); ++ odm_set_bb_reg(dm, R_0xc18, 0xff00, offset_q_hex[1]); ++ } ++ } else if (dm->support_ic_type & (ODM_RTL8721D)) { ++ /*judy modified 20180517*/ ++ offset_i_hex[0] = (reg_value32[0] & 0xff800) >> 11; ++ offset_q_hex[0] = (reg_value32[0] & 0x3fe) >> 1; ++ ++ /*@Before filling into registers, ++ *offset should be multiplexed (-1) ++ */ ++ offset_i_hex[0] = 0x200 - offset_i_hex[0]; ++ offset_q_hex[0] = 0x200 - offset_q_hex[0]; ++ ++ odm_set_bb_reg(dm, R_0x950, 0x1ff, offset_i_hex[0]); ++ odm_set_bb_reg(dm, R_0x950, 0x1ff0000, offset_q_hex[0]); ++ } ++#endif ++} ++ ++void phydm_receiver_blocking(void *dm_void) ++{ ++#ifdef CONFIG_RECEIVER_BLOCKING ++ struct dm_struct *dm = (struct dm_struct *)dm_void; ++ u32 chnl = *dm->channel; ++ u8 bw = *dm->band_width; ++ u32 bb_regf0 = odm_get_bb_reg(dm, R_0xf0, 0xf000); ++ ++ if (!(dm->support_ic_type & ODM_RECEIVER_BLOCKING_SUPPORT) || ++ !(dm->support_ability & ODM_BB_ADAPTIVITY)) ++ return; ++ ++ if ((dm->support_ic_type & ODM_RTL8188E && bb_regf0 < 8) || ++ dm->support_ic_type & ODM_RTL8192E) { ++ /*@8188E_T version*/ ++ if (dm->consecutive_idlel_time <= 10 || *dm->mp_mode) ++ goto end; ++ ++ if (bw == CHANNEL_WIDTH_20 && chnl == 1) { ++ phydm_nbi_setting(dm, FUNC_ENABLE, chnl, 20, 2410, ++ PHYDM_DONT_CARE); ++ dm->is_rx_blocking_en = true; ++ } else if ((bw == CHANNEL_WIDTH_20) && (chnl == 13)) { ++ phydm_nbi_setting(dm, FUNC_ENABLE, chnl, 20, 2473, ++ PHYDM_DONT_CARE); ++ dm->is_rx_blocking_en = true; ++ } else if (dm->is_rx_blocking_en && chnl != 1 && chnl != 13) { ++ phydm_nbi_enable(dm, FUNC_DISABLE); ++ odm_set_bb_reg(dm, R_0xc40, 0x1f000000, 0x1f); ++ dm->is_rx_blocking_en = false; ++ } ++ return; ++ } else if ((dm->support_ic_type & ODM_RTL8188E && bb_regf0 >= 8)) { ++ /*@8188E_S version*/ ++ if (dm->consecutive_idlel_time <= 10 || *dm->mp_mode) ++ goto end; ++ ++ if (bw == CHANNEL_WIDTH_20 && chnl == 13) { ++ phydm_nbi_setting(dm, FUNC_ENABLE, chnl, 20, 2473, ++ PHYDM_DONT_CARE); ++ dm->is_rx_blocking_en = true; ++ } else if (dm->is_rx_blocking_en && chnl != 13) { ++ phydm_nbi_enable(dm, FUNC_DISABLE); ++ odm_set_bb_reg(dm, R_0xc40, 0x1f000000, 0x1f); ++ dm->is_rx_blocking_en = false; ++ } ++ return; ++ } ++ ++end: ++ if (dm->is_rx_blocking_en) { ++ phydm_nbi_enable(dm, FUNC_DISABLE); ++ odm_set_bb_reg(dm, R_0xc40, 0x1f000000, 0x1f); ++ dm->is_rx_blocking_en = false; ++ } ++#endif ++} +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_cck_pd.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_cck_pd.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_cck_pd.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_cck_pd.c 2021-03-07 18:16:17.061956384 +0200 @@ -0,0 +1,1086 @@ +/****************************************************************************** + * @@ -222434,11 +217752,9 @@ index 000000000..8f5229abf +} +#endif /*#ifdef PHYDM_SUPPORT_CCKPD*/ + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_cck_pd.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_cck_pd.h -new file mode 100644 -index 000000000..f8c8625df ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_cck_pd.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_cck_pd.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_cck_pd.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_cck_pd.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_cck_pd.h 2021-03-07 18:16:17.061956384 +0200 @@ -0,0 +1,155 @@ +/****************************************************************************** + * @@ -222595,11 +217911,9 @@ index 000000000..f8c8625df + +void phydm_cck_pd_init(void *dm_void); +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_ccx.c linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_ccx.c -new file mode 100644 -index 000000000..f9ea9bb99 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_ccx.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_ccx.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_ccx.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_ccx.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_ccx.c 2021-03-07 18:16:17.061956384 +0200 @@ -0,0 +1,1802 @@ +/****************************************************************************** + * @@ -224403,11 +219717,9 @@ index 000000000..f9ea9bb99 + *_out_len = out_len; +} + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_ccx.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_ccx.h -new file mode 100644 -index 000000000..2b3d1da6b ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_ccx.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_ccx.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_ccx.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_ccx.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_ccx.h 2021-03-07 18:16:17.061956384 +0200 @@ -0,0 +1,268 @@ +/****************************************************************************** + * @@ -224677,11 +219989,9 @@ index 000000000..2b3d1da6b + char *output, u32 *_out_len); + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_cfotracking.c linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_cfotracking.c -new file mode 100644 -index 000000000..95d89e379 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_cfotracking.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_cfotracking.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_cfotracking.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_cfotracking.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_cfotracking.c 2021-03-07 18:16:17.061956384 +0200 @@ -0,0 +1,594 @@ +/****************************************************************************** + * @@ -225277,11 +220587,9 @@ index 000000000..95d89e379 + *_out_len = out_len; +} + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_cfotracking.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_cfotracking.h -new file mode 100644 -index 000000000..080c29316 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_cfotracking.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_cfotracking.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_cfotracking.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_cfotracking.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_cfotracking.h 2021-03-07 18:16:17.061956384 +0200 @@ -0,0 +1,73 @@ +/****************************************************************************** + * @@ -225356,11 +220664,9 @@ index 000000000..080c29316 +void phy_Init_crystal_capacity(void *dm_void, u8 crystal_cap); +#endif +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_debug.c linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_debug.c -new file mode 100644 -index 000000000..57d24e0e6 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_debug.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_debug.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_debug.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_debug.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_debug.c 2021-03-07 18:16:17.062956431 +0200 @@ -0,0 +1,4728 @@ +/****************************************************************************** + * @@ -230090,11 +225396,9 @@ index 000000000..57d24e0e6 +#endif +#endif /*@#ifdef CONFIG_PHYDM_DEBUG_FUNCTION*/ +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_debug.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_debug.h -new file mode 100644 -index 000000000..a795f30d7 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_debug.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_debug.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_debug.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_debug.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_debug.h 2021-03-07 18:16:17.062956431 +0200 @@ -0,0 +1,480 @@ +/****************************************************************************** + * @@ -230576,11 +225880,9 @@ index 000000000..a795f30d7 +void phydm_fw_trace_handler_8051(void *dm_void, u8 *cmd_buf, u8 cmd_len); + +#endif /* @__ODM_DBG_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_dfs.c linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_dfs.c -new file mode 100644 -index 000000000..39c387942 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_dfs.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_dfs.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_dfs.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_dfs.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_dfs.c 2021-03-07 18:16:17.062956431 +0200 @@ -0,0 +1,2323 @@ +/****************************************************************************** + * @@ -232905,11 +228207,9 @@ index 000000000..39c387942 +} +#endif +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_dfs.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_dfs.h -new file mode 100644 -index 000000000..a1a96db5f ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_dfs.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_dfs.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_dfs.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_dfs.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_dfs.h 2021-03-07 18:16:17.062956431 +0200 @@ -0,0 +1,190 @@ +/****************************************************************************** + * @@ -233101,11 +228401,9 @@ index 000000000..a1a96db5f +#endif + +#endif /*@#ifndef __PHYDM_DFS_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_dig.c linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_dig.c -new file mode 100644 -index 000000000..eea6dcee4 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_dig.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_dig.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_dig.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_dig.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_dig.c 2021-03-07 18:16:17.062956431 +0200 @@ -0,0 +1,2858 @@ +/****************************************************************************** + * @@ -235965,11 +231263,9 @@ index 000000000..eea6dcee4 +} +#endif /*#if (RTL8822B_SUPPORT)*/ +#endif /*#ifdef CONFIG_MCC_DM*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_dig.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_dig.h -new file mode 100644 -index 000000000..9800980af ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_dig.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_dig.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_dig.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_dig.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_dig.h 2021-03-07 18:16:17.062956431 +0200 @@ -0,0 +1,337 @@ +/****************************************************************************** + * @@ -236308,11 +231604,9 @@ index 000000000..9800980af + + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_dynamictxpower.c linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_dynamictxpower.c -new file mode 100644 -index 000000000..ceed35fe8 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_dynamictxpower.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_dynamictxpower.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_dynamictxpower.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_dynamictxpower.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_dynamictxpower.c 2021-03-07 18:16:17.062956431 +0200 @@ -0,0 +1,517 @@ +/****************************************************************************** + * @@ -236831,11 +232125,9 @@ index 000000000..ceed35fe8 +} +#endif /*@#if (DM_ODM_SUPPORT_TYPE == ODM_WIN)*/ +#endif /* @#ifdef CONFIG_DYNAMIC_TX_TWR */ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_dynamictxpower.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_dynamictxpower.h -new file mode 100644 -index 000000000..3906b72c1 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_dynamictxpower.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_dynamictxpower.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_dynamictxpower.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_dynamictxpower.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_dynamictxpower.h 2021-03-07 18:16:17.062956431 +0200 @@ -0,0 +1,103 @@ +/****************************************************************************** + * @@ -236940,89 +232232,9 @@ index 000000000..3906b72c1 + +#endif +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_features.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_features.h -new file mode 100644 -index 000000000..afb18393e ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_features.h -@@ -0,0 +1,72 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * The full GNU General Public License is included in this distribution in the -+ * file called LICENSE. -+ * -+ * Contact Information: -+ * wlanfae -+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, -+ * Hsinchu 300, Taiwan. -+ * -+ * Larry Finger -+ * -+ *****************************************************************************/ -+ -+#ifndef __PHYDM_FEATURES_H__ -+#define __PHYDM_FEATURES_H__ -+ -+#define CONFIG_RUN_IN_DRV -+#define ODM_DC_CANCELLATION_SUPPORT (ODM_RTL8188F | \ -+ ODM_RTL8710B | \ -+ ODM_RTL8192F | \ -+ ODM_RTL8821C | \ -+ ODM_RTL8721D) -+#define ODM_RECEIVER_BLOCKING_SUPPORT (ODM_RTL8188E | ODM_RTL8192E) -+ -+/*@20170103 YuChen add for FW API*/ -+#define PHYDM_FW_API_ENABLE_8822B 1 -+#define PHYDM_FW_API_FUNC_ENABLE_8822B 1 -+#define PHYDM_FW_API_ENABLE_8821C 1 -+#define PHYDM_FW_API_FUNC_ENABLE_8821C 1 -+#define PHYDM_FW_API_ENABLE_8195B 1 -+#define PHYDM_FW_API_FUNC_ENABLE_8195B 1 -+#define PHYDM_FW_API_ENABLE_8198F 1 -+#define PHYDM_FW_API_FUNC_ENABLE_8198F 1 -+#define PHYDM_FW_API_ENABLE_8822C 1 -+#define PHYDM_FW_API_FUNC_ENABLE_8822C 1 -+#define PHYDM_FW_API_ENABLE_8814B 1 -+#define PHYDM_FW_API_FUNC_ENABLE_8814B 1 -+#define PHYDM_FW_API_ENABLE_8812F 1 -+#define PHYDM_FW_API_FUNC_ENABLE_8812F 1 -+ -+#define CONFIG_POWERSAVING 0 -+ -+#ifdef BEAMFORMING_SUPPORT -+#if (BEAMFORMING_SUPPORT) -+ #define PHYDM_BEAMFORMING_SUPPORT -+#endif -+#endif -+ -+#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) -+ #include "phydm_features_win.h" -+#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) -+ #include "phydm_features_ce.h" -+ /*@#include "phydm_features_ce2_kernel.h"*/ -+#elif (DM_ODM_SUPPORT_TYPE == ODM_AP) -+ #include "phydm_features_ap.h" -+#elif (DM_ODM_SUPPORT_TYPE == ODM_IOT) -+ #include "phydm_features_iot.h" -+#endif -+ -+#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_features_ap.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_features_ap.h -new file mode 100644 -index 000000000..db2c3d27e ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_features_ap.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_features_ap.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_features_ap.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_features_ap.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_features_ap.h 2021-03-07 18:16:17.062956431 +0200 @@ -0,0 +1,196 @@ +/****************************************************************************** + * @@ -237220,11 +232432,97 @@ index 000000000..db2c3d27e +#endif + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_features_ce.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_features_ce.h -new file mode 100644 -index 000000000..6c12436c8 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_features_ce.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_features_ce2_kernel.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_features_ce2_kernel.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_features_ce2_kernel.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_features_ce2_kernel.h 2021-03-07 18:16:17.062956431 +0200 +@@ -0,0 +1,84 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, ++ * Hsinchu 300, Taiwan. ++ * ++ * Larry Finger ++ * ++ *****************************************************************************/ ++ ++#ifndef __PHYDM_FEATURES_CE_H__ ++#define __PHYDM_FEATURES_CE_H__ ++ ++#define PHYDM_LA_MODE_SUPPORT 0 ++ ++#if (RTL8822B_SUPPORT || RTL8812A_SUPPORT || RTL8197F_SUPPORT ||\ ++ RTL8192F_SUPPORT) ++ #define DYN_ANT_WEIGHTING_SUPPORT ++#endif ++ ++#if (RTL8822B_SUPPORT || RTL8821C_SUPPORT) ++ #define FAHM_SUPPORT ++#endif ++ #define NHM_SUPPORT ++ #define CLM_SUPPORT ++ ++#if (RTL8822B_SUPPORT) ++ #define PHYDM_TXA_CALIBRATION ++#endif ++ ++#if (RTL8188F_SUPPORT || RTL8710B_SUPPORT || RTL8821C_SUPPORT ||\ ++ RTL8822B_SUPPORT || RTL8192F_SUPPORT) ++ #define PHYDM_DC_CANCELLATION ++#endif ++ ++#if (RTL8192F_SUPPORT == 1) ++ /*#define CONFIG_8912F_SPUR_CALIBRATION*/ ++#endif ++ ++#if (RTL8822B_SUPPORT == 1) ++ /* #define CONFIG_8822B_SPUR_CALIBRATION */ ++#endif ++ ++#define PHYDM_SUPPORT_CCKPD ++#define PHYDM_SUPPORT_ADAPTIVITY ++ ++#ifdef CONFIG_DFS_MASTER ++ #define CONFIG_PHYDM_DFS_MASTER ++#endif ++ ++#define CONFIG_BB_TXBF_API ++#define CONFIG_PHYDM_DEBUG_FUNCTION ++ ++#ifdef CONFIG_BT_COEXIST ++ #define ODM_CONFIG_BT_COEXIST ++#endif ++#define PHYDM_SUPPORT_RSSI_MONITOR ++#define CFG_DIG_DAMPING_CHK ++ ++ ++#ifdef PHYDM_BEAMFORMING_SUPPORT ++ #if (RTL8192F_SUPPORT || RTL8195B_SUPPORT || RTL8821C_SUPPORT ||\ ++ RTL8822B_SUPPORT || RTL8197F_SUPPORT || RTL8198F_SUPPORT ||\ ++ RTL8822C_SUPPORT || RTL8814B_SUPPORT) ++ #define DRIVER_BEAMFORMING_VERSION2 ++ #endif ++#endif ++ ++#endif +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_features_ce.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_features_ce.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_features_ce.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_features_ce.h 2021-03-07 18:16:17.062956431 +0200 @@ -0,0 +1,214 @@ +/****************************************************************************** + * @@ -237440,12 +232738,10 @@ index 000000000..6c12436c8 + + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_features_ce2_kernel.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_features_ce2_kernel.h -new file mode 100644 -index 000000000..c206ea605 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_features_ce2_kernel.h -@@ -0,0 +1,84 @@ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_features.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_features.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_features.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_features.h 2021-03-07 18:16:17.062956431 +0200 +@@ -0,0 +1,72 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -237471,70 +232767,56 @@ index 000000000..c206ea605 + * + *****************************************************************************/ + -+#ifndef __PHYDM_FEATURES_CE_H__ -+#define __PHYDM_FEATURES_CE_H__ ++#ifndef __PHYDM_FEATURES_H__ ++#define __PHYDM_FEATURES_H__ + -+#define PHYDM_LA_MODE_SUPPORT 0 ++#define CONFIG_RUN_IN_DRV ++#define ODM_DC_CANCELLATION_SUPPORT (ODM_RTL8188F | \ ++ ODM_RTL8710B | \ ++ ODM_RTL8192F | \ ++ ODM_RTL8821C | \ ++ ODM_RTL8721D) ++#define ODM_RECEIVER_BLOCKING_SUPPORT (ODM_RTL8188E | ODM_RTL8192E) + -+#if (RTL8822B_SUPPORT || RTL8812A_SUPPORT || RTL8197F_SUPPORT ||\ -+ RTL8192F_SUPPORT) -+ #define DYN_ANT_WEIGHTING_SUPPORT ++/*@20170103 YuChen add for FW API*/ ++#define PHYDM_FW_API_ENABLE_8822B 1 ++#define PHYDM_FW_API_FUNC_ENABLE_8822B 1 ++#define PHYDM_FW_API_ENABLE_8821C 1 ++#define PHYDM_FW_API_FUNC_ENABLE_8821C 1 ++#define PHYDM_FW_API_ENABLE_8195B 1 ++#define PHYDM_FW_API_FUNC_ENABLE_8195B 1 ++#define PHYDM_FW_API_ENABLE_8198F 1 ++#define PHYDM_FW_API_FUNC_ENABLE_8198F 1 ++#define PHYDM_FW_API_ENABLE_8822C 1 ++#define PHYDM_FW_API_FUNC_ENABLE_8822C 1 ++#define PHYDM_FW_API_ENABLE_8814B 1 ++#define PHYDM_FW_API_FUNC_ENABLE_8814B 1 ++#define PHYDM_FW_API_ENABLE_8812F 1 ++#define PHYDM_FW_API_FUNC_ENABLE_8812F 1 ++ ++#define CONFIG_POWERSAVING 0 ++ ++#ifdef BEAMFORMING_SUPPORT ++#if (BEAMFORMING_SUPPORT) ++ #define PHYDM_BEAMFORMING_SUPPORT ++#endif +#endif + -+#if (RTL8822B_SUPPORT || RTL8821C_SUPPORT) -+ #define FAHM_SUPPORT -+#endif -+ #define NHM_SUPPORT -+ #define CLM_SUPPORT -+ -+#if (RTL8822B_SUPPORT) -+ #define PHYDM_TXA_CALIBRATION -+#endif -+ -+#if (RTL8188F_SUPPORT || RTL8710B_SUPPORT || RTL8821C_SUPPORT ||\ -+ RTL8822B_SUPPORT || RTL8192F_SUPPORT) -+ #define PHYDM_DC_CANCELLATION -+#endif -+ -+#if (RTL8192F_SUPPORT == 1) -+ /*#define CONFIG_8912F_SPUR_CALIBRATION*/ -+#endif -+ -+#if (RTL8822B_SUPPORT == 1) -+ /* #define CONFIG_8822B_SPUR_CALIBRATION */ -+#endif -+ -+#define PHYDM_SUPPORT_CCKPD -+#define PHYDM_SUPPORT_ADAPTIVITY -+ -+#ifdef CONFIG_DFS_MASTER -+ #define CONFIG_PHYDM_DFS_MASTER -+#endif -+ -+#define CONFIG_BB_TXBF_API -+#define CONFIG_PHYDM_DEBUG_FUNCTION -+ -+#ifdef CONFIG_BT_COEXIST -+ #define ODM_CONFIG_BT_COEXIST -+#endif -+#define PHYDM_SUPPORT_RSSI_MONITOR -+#define CFG_DIG_DAMPING_CHK -+ -+ -+#ifdef PHYDM_BEAMFORMING_SUPPORT -+ #if (RTL8192F_SUPPORT || RTL8195B_SUPPORT || RTL8821C_SUPPORT ||\ -+ RTL8822B_SUPPORT || RTL8197F_SUPPORT || RTL8198F_SUPPORT ||\ -+ RTL8822C_SUPPORT || RTL8814B_SUPPORT) -+ #define DRIVER_BEAMFORMING_VERSION2 -+ #endif ++#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) ++ #include "phydm_features_win.h" ++#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ #include "phydm_features_ce.h" ++ /*@#include "phydm_features_ce2_kernel.h"*/ ++#elif (DM_ODM_SUPPORT_TYPE == ODM_AP) ++ #include "phydm_features_ap.h" ++#elif (DM_ODM_SUPPORT_TYPE == ODM_IOT) ++ #include "phydm_features_iot.h" +#endif + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_features_iot.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_features_iot.h -new file mode 100644 -index 000000000..a74d571a1 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_features_iot.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_features_iot.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_features_iot.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_features_iot.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_features_iot.h 2021-03-07 18:16:17.062956431 +0200 @@ -0,0 +1,174 @@ +/****************************************************************************** + * @@ -237710,11 +232992,9 @@ index 000000000..a74d571a1 +#endif + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_features_win.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_features_win.h -new file mode 100644 -index 000000000..8d2d13109 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_features_win.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_features_win.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_features_win.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_features_win.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_features_win.h 2021-03-07 18:16:17.062956431 +0200 @@ -0,0 +1,185 @@ +/****************************************************************************** + * @@ -237901,11 +233181,1369 @@ index 000000000..8d2d13109 +#endif + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_hwconfig.c linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_hwconfig.c -new file mode 100644 -index 000000000..4c4d9386e ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_hwconfig.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm.h 2021-03-07 18:16:17.059956289 +0200 +@@ -0,0 +1,1356 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, ++ * Hsinchu 300, Taiwan. ++ * ++ * Larry Finger ++ * ++ *****************************************************************************/ ++ ++#ifndef __HALDMOUTSRC_H__ ++#define __HALDMOUTSRC_H__ ++ ++/*@============================================================*/ ++/*@include files*/ ++/*@============================================================*/ ++/*PHYDM header*/ ++#include "phydm_pre_define.h" ++#include "phydm_features.h" ++#include "phydm_dig.h" ++#ifdef CONFIG_PATH_DIVERSITY ++#include "phydm_pathdiv.h" ++#endif ++#ifdef CONFIG_PHYDM_ANTENNA_DIVERSITY ++#include "phydm_antdiv.h" ++#endif ++ ++#include "phydm_soml.h" ++ ++#ifdef CONFIG_SMART_ANTENNA ++#include "phydm_smt_ant.h" ++#endif ++#ifdef CONFIG_ANT_DETECTION ++#include "phydm_antdect.h" ++#endif ++#include "phydm_rainfo.h" ++#ifdef CONFIG_DYNAMIC_TX_TWR ++#include "phydm_dynamictxpower.h" ++#endif ++#include "phydm_cfotracking.h" ++#include "phydm_adaptivity.h" ++#include "phydm_dfs.h" ++#include "phydm_ccx.h" ++#include "txbf/phydm_hal_txbf_api.h" ++#if (PHYDM_LA_MODE_SUPPORT == 1) ++#include "phydm_adc_sampling.h" ++#endif ++#ifdef CONFIG_PSD_TOOL ++#include "phydm_psd.h" ++#endif ++#ifdef PHYDM_PRIMARY_CCA ++#include "phydm_primary_cca.h" ++#endif ++#include "phydm_cck_pd.h" ++#include "phydm_rssi_monitor.h" ++#ifdef PHYDM_AUTO_DEGBUG ++#include "phydm_auto_dbg.h" ++#endif ++#include "phydm_math_lib.h" ++#include "phydm_noisemonitor.h" ++#include "phydm_api.h" ++#ifdef PHYDM_POWER_TRAINING_SUPPORT ++#include "phydm_pow_train.h" ++#endif ++#ifdef PHYDM_LNA_SAT_CHK_SUPPORT ++#include "phydm_lna_sat.h" ++#endif ++#ifdef PHYDM_PMAC_TX_SETTING_SUPPORT ++#include "phydm_pmac_tx_setting.h" ++#endif ++#ifdef PHYDM_MP_SUPPORT ++#include "phydm_mp.h" ++#endif ++#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE)) ++ #include "phydm_beamforming.h" ++#endif ++ ++#include "phydm_regtable.h" ++ ++/*@HALRF header*/ ++#include "halrf/halrf_iqk.h" ++#include "halrf/halrf_dpk.h" ++#include "halrf/halrf.h" ++#include "halrf/halrf_powertracking.h" ++#if (DM_ODM_SUPPORT_TYPE & (ODM_AP)) ++ #include "halrf/halphyrf_ap.h" ++#elif(DM_ODM_SUPPORT_TYPE & (ODM_CE)) ++ #include "halrf/halphyrf_ce.h" ++#elif (DM_ODM_SUPPORT_TYPE & (ODM_WIN)) ++ #include "halrf/halphyrf_win.h" ++#elif(DM_ODM_SUPPORT_TYPE & (ODM_IOT)) ++ #include "halrf/halphyrf_iot.h" ++#endif ++ ++extern const u16 phy_rate_table[28]; ++ ++/*@============================================================*/ ++/*@Definition */ ++/*@============================================================*/ ++ ++/* Traffic load decision */ ++#define TRAFFIC_NO_TP 0 ++#define TRAFFIC_ULTRA_LOW 1 ++#define TRAFFIC_LOW 2 ++#define TRAFFIC_MID 3 ++#define TRAFFIC_HIGH 4 ++ ++#define NONE 0 ++ ++#if defined(DM_ODM_CE_MAC80211) ++#define MAX_2(x, y) \ ++ __max2(typeof(x), typeof(y), \ ++ x, y) ++#define __max2(t1, t2, x, y) ({ \ ++ t1 m80211_max1 = (x); \ ++ t2 m80211_max2 = (y); \ ++ m80211_max1 > m80211_max2 ? m80211_max1 : m80211_max2; }) ++ ++#define MIN_2(x, y) \ ++ __min2(typeof(x), typeof(y), \ ++ x, y) ++#define __min2(t1, t2, x, y) ({ \ ++ t1 m80211_min1 = (x); \ ++ t2 m80211_min2 = (y); \ ++ m80211_min1 < m80211_min2 ? m80211_min1 : m80211_min2; }) ++ ++#define DIFF_2(x, y) \ ++ __diff2(typeof(x), typeof(y), \ ++ x, y) ++#define __diff2(t1, t2, x, y) ({ \ ++ t1 __d1 = (x); \ ++ t2 __d2 = (y); \ ++ (__d1 >= __d2) ? (__d1 - __d2) : (__d2 - __d1); }) ++#else ++#define MAX_2(_x_, _y_) (((_x_) > (_y_)) ? (_x_) : (_y_)) ++#define MIN_2(_x_, _y_) (((_x_) < (_y_)) ? (_x_) : (_y_)) ++#define DIFF_2(_x_, _y_) ((_x_ >= _y_) ? (_x_ - _y_) : (_y_ - _x_)) ++#endif ++ ++#define IS_GREATER(_x_, _y_) (((_x_) >= (_y_)) ? true : false) ++#define IS_LESS(_x_, _y_) (((_x_) < (_y_)) ? true : false) ++ ++#if defined(DM_ODM_CE_MAC80211) ++#define BYTE_DUPLICATE_2_DWORD(B0) ({ \ ++ u32 __b_dup = (B0);\ ++ (((__b_dup) << 24) | ((__b_dup) << 16) | ((__b_dup) << 8) | (__b_dup));\ ++ }) ++#else ++#define BYTE_DUPLICATE_2_DWORD(B0) \ ++ (((B0) << 24) | ((B0) << 16) | ((B0) << 8) | (B0)) ++#endif ++#define BYTE_2_DWORD(B3, B2, B1, B0) \ ++ (((B3) << 24) | ((B2) << 16) | ((B1) << 8) | (B0)) ++#define BIT_2_BYTE(B3, B2, B1, B0) \ ++ (((B3) << 3) | ((B2) << 2) | ((B1) << 1) | (B0)) ++ ++/*@For cmn sta info*/ ++#if defined(DM_ODM_CE_MAC80211) ++#define is_sta_active(sta) ({ \ ++ struct cmn_sta_info *__sta = (sta); \ ++ ((__sta) && (__sta->dm_ctrl & STA_DM_CTRL_ACTIVE)); \ ++ }) ++ ++#define IS_FUNC_EN(name) ({ \ ++ u8 *__is_func_name = (name); \ ++ (__is_func_name) && (*__is_func_name); \ ++ }) ++#else ++#define is_sta_active(sta) ((sta) && (sta->dm_ctrl & STA_DM_CTRL_ACTIVE)) ++ ++#define IS_FUNC_EN(name) ((name) && (*name)) ++#endif ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_AP) ++ #define PHYDM_WATCH_DOG_PERIOD 1 /*second*/ ++#else ++ #define PHYDM_WATCH_DOG_PERIOD 2 /*second*/ ++#endif ++ ++#define PHY_HIST_SIZE 12 ++ ++/*@============================================================*/ ++/*structure and define*/ ++/*@============================================================*/ ++ ++#define dm_type_by_fw 0 ++#define dm_type_by_driver 1 ++ ++#ifdef BB_RAM_SUPPORT ++ ++struct phydm_bb_ram_per_sta { ++ /* @Reg0x1E84 for RAM I/O*/ ++ boolean hw_igi_en; ++ boolean tx_pwr_offset0_en; ++ boolean tx_pwr_offset1_en; ++ /* @ macid from 0 to 63, above 63 => mapping to 63*/ ++ u8 macid_addr; ++ /* @hw_igi value for paths after packet Tx in a period of time*/ ++ u8 hw_igi; ++ /* @tx_pwr_offset0 offset for Tx power index*/ ++ s8 tx_pwr_offset0; ++ s8 tx_pwr_offset1; ++ ++}; ++ ++struct phydm_bb_ram_ctrl { ++ /*@ For 98F/14B/22C/12F, each TxAGC step will be 0.25dB*/ ++ struct phydm_bb_ram_per_sta pram_sta_ctrl[ODM_ASSOCIATE_ENTRY_NUM]; ++ /*------------ For table2 do not set power offset by macid --------*/ ++ /* For type == 2'b10, 0x1e70[22:16] = tx_pwr_offset_reg0, 0x1e70[23] = enable */ ++ boolean tx_pwr_offset_reg0_en; ++ u8 tx_pwr_offset_reg0; ++ /* For type == 2'b11, 0x1e70[30:24] = tx_pwr_offset_reg1, 0x1e70[31] = enable */ ++ boolean tx_pwr_offset_reg1_en; ++ u8 tx_pwr_offset_reg1; ++}; ++ ++#endif ++ ++struct phydm_phystatus_statistic { ++ /*@[CCK]*/ ++ u32 rssi_cck_sum; ++ u32 rssi_cck_cnt; ++ /*@[OFDM]*/ ++ u32 rssi_ofdm_sum; ++ u32 rssi_ofdm_cnt; ++ u32 evm_ofdm_sum; ++ u32 snr_ofdm_sum; ++ u16 evm_ofdm_hist[PHY_HIST_SIZE]; ++ u16 snr_ofdm_hist[PHY_HIST_SIZE]; ++ /*@[1SS]*/ ++ u32 rssi_1ss_cnt; ++ u32 rssi_1ss_sum; ++ u32 evm_1ss_sum; ++ u32 snr_1ss_sum; ++ u16 evm_1ss_hist[PHY_HIST_SIZE]; ++ u16 snr_1ss_hist[PHY_HIST_SIZE]; ++ /*@[2SS]*/ ++ #if (defined(PHYDM_COMPILE_ABOVE_2SS)) ++ u32 rssi_2ss_cnt; ++ u32 rssi_2ss_sum[2]; ++ u32 evm_2ss_sum[2]; ++ u32 snr_2ss_sum[2]; ++ u16 evm_2ss_hist[2][PHY_HIST_SIZE]; ++ u16 snr_2ss_hist[2][PHY_HIST_SIZE]; ++ #endif ++ /*@[3SS]*/ ++ #if (defined(PHYDM_COMPILE_ABOVE_3SS)) ++ u32 rssi_3ss_cnt; ++ u32 rssi_3ss_sum[3]; ++ u32 evm_3ss_sum[3]; ++ u32 snr_3ss_sum[3]; ++ u16 evm_3ss_hist[3][PHY_HIST_SIZE]; ++ u16 snr_3ss_hist[3][PHY_HIST_SIZE]; ++ #endif ++ /*@[4SS]*/ ++ #if (defined(PHYDM_COMPILE_ABOVE_4SS)) ++ u32 rssi_4ss_cnt; ++ u32 rssi_4ss_sum[4]; ++ u32 evm_4ss_sum[4]; ++ u32 snr_4ss_sum[4]; ++ u16 evm_4ss_hist[4][PHY_HIST_SIZE]; ++ u16 snr_4ss_hist[4][PHY_HIST_SIZE]; ++ #endif ++}; ++ ++struct phydm_phystatus_avg { ++ /*@[CCK]*/ ++ u8 rssi_cck_avg; ++ /*@[OFDM]*/ ++ u8 rssi_ofdm_avg; ++ u8 evm_ofdm_avg; ++ u8 snr_ofdm_avg; ++ /*@[1SS]*/ ++ u8 rssi_1ss_avg; ++ u8 evm_1ss_avg; ++ u8 snr_1ss_avg; ++ /*@[2SS]*/ ++ #if (defined(PHYDM_COMPILE_ABOVE_2SS)) ++ u8 rssi_2ss_avg[2]; ++ u8 evm_2ss_avg[2]; ++ u8 snr_2ss_avg[2]; ++ #endif ++ /*@[3SS]*/ ++ #if (defined(PHYDM_COMPILE_ABOVE_3SS)) ++ u8 rssi_3ss_avg[3]; ++ u8 evm_3ss_avg[3]; ++ u8 snr_3ss_avg[3]; ++ #endif ++ /*@[4SS]*/ ++ #if (defined(PHYDM_COMPILE_ABOVE_4SS)) ++ u8 rssi_4ss_avg[4]; ++ u8 evm_4ss_avg[4]; ++ u8 snr_4ss_avg[4]; ++ #endif ++}; ++ ++struct odm_phy_dbg_info { ++ /*@ODM Write,debug info*/ ++ u32 num_qry_phy_status_cck; ++ u32 num_qry_phy_status_ofdm; ++#if (ODM_PHY_STATUS_NEW_TYPE_SUPPORT == 1) || (defined(PHYSTS_3RD_TYPE_SUPPORT)) ++ u32 num_qry_mu_pkt; ++ u32 num_qry_bf_pkt; ++ u16 num_mu_vht_pkt[VHT_RATE_NUM]; ++ boolean is_ldpc_pkt; ++ boolean is_stbc_pkt; ++ u8 num_of_ppdu[4]; ++ u8 gid_num[4]; ++#endif ++ u32 condi_num; /*@condition number U(18,4)*/ ++ u8 condi_num_cdf[CN_CNT_MAX]; ++ u8 num_qry_beacon_pkt; ++ u8 beacon_cnt_in_period; /*@beacon cnt within watchdog period*/ ++ u8 beacon_phy_rate; ++ u8 show_phy_sts_all_pkt; /*@Show phy status witch not match BSSID*/ ++ u16 show_phy_sts_max_cnt; /*@show number of phy-status row data per PHYDM watchdog*/ ++ u16 show_phy_sts_cnt; ++ u16 num_qry_legacy_pkt[LEGACY_RATE_NUM]; ++ u16 num_qry_ht_pkt[HT_RATE_NUM]; ++ u16 num_qry_pkt_sc_20m[LOW_BW_RATE_NUM]; /*@20M SC*/ ++ boolean ht_pkt_not_zero; ++ boolean low_bw_20_occur; ++ #if ODM_IC_11AC_SERIES_SUPPORT || defined(PHYDM_IC_JGR3_SERIES_SUPPORT) ++ u16 num_qry_vht_pkt[VHT_RATE_NUM]; ++ u16 num_qry_pkt_sc_40m[LOW_BW_RATE_NUM]; /*@40M SC*/ ++ boolean vht_pkt_not_zero; ++ boolean low_bw_40_occur; ++ #endif ++ u16 snr_hist_th[PHY_HIST_SIZE - 1]; ++ u16 evm_hist_th[PHY_HIST_SIZE - 1]; ++ #ifdef PHYDM_IC_JGR3_SERIES_SUPPORT ++ s16 cfo_tail[4]; /* per-path's cfo_tail */ ++ #endif ++ struct phydm_phystatus_statistic physts_statistic_info; ++ struct phydm_phystatus_avg phystatus_statistic_avg; ++}; ++ ++enum odm_cmninfo { ++ /*@Fixed value*/ ++ /*@-----------HOOK BEFORE REG INIT-----------*/ ++ ODM_CMNINFO_PLATFORM = 0, ++ ODM_CMNINFO_ABILITY, ++ ODM_CMNINFO_INTERFACE, ++ ODM_CMNINFO_MP_TEST_CHIP, ++ ODM_CMNINFO_IC_TYPE, ++ ODM_CMNINFO_CUT_VER, ++ ODM_CMNINFO_FAB_VER, ++ ODM_CMNINFO_FW_VER, ++ ODM_CMNINFO_FW_SUB_VER, ++ ODM_CMNINFO_RF_TYPE, ++ ODM_CMNINFO_RFE_TYPE, ++ ODM_CMNINFO_DPK_EN, ++ ODM_CMNINFO_BOARD_TYPE, ++ ODM_CMNINFO_PACKAGE_TYPE, ++ ODM_CMNINFO_EXT_LNA, ++ ODM_CMNINFO_5G_EXT_LNA, ++ ODM_CMNINFO_EXT_PA, ++ ODM_CMNINFO_5G_EXT_PA, ++ ODM_CMNINFO_GPA, ++ ODM_CMNINFO_APA, ++ ODM_CMNINFO_GLNA, ++ ODM_CMNINFO_ALNA, ++ ODM_CMNINFO_TDMA, ++ ODM_CMNINFO_EXT_TRSW, ++ ODM_CMNINFO_EXT_LNA_GAIN, ++ ODM_CMNINFO_PATCH_ID, ++ ODM_CMNINFO_BINHCT_TEST, ++ ODM_CMNINFO_BWIFI_TEST, ++ ODM_CMNINFO_SMART_CONCURRENT, ++ ODM_CMNINFO_CONFIG_BB_RF, ++ ODM_CMNINFO_IQKPAOFF, ++ ODM_CMNINFO_HUBUSBMODE, ++ ODM_CMNINFO_FWDWRSVDPAGEINPROGRESS, ++ ODM_CMNINFO_TX_TP, ++ ODM_CMNINFO_RX_TP, ++ ODM_CMNINFO_SOUNDING_SEQ, ++ ODM_CMNINFO_REGRFKFREEENABLE, ++ ODM_CMNINFO_RFKFREEENABLE, ++ ODM_CMNINFO_NORMAL_RX_PATH_CHANGE, ++ ODM_CMNINFO_EFUSE0X3D8, ++ ODM_CMNINFO_EFUSE0X3D7, ++ ODM_CMNINFO_SOFT_AP_SPECIAL_SETTING, ++ ODM_CMNINFO_X_CAP_SETTING, ++ ODM_CMNINFO_ADVANCE_OTA, ++ ODM_CMNINFO_HP_HWID, ++ /*@-----------HOOK BEFORE REG INIT-----------*/ ++ ++ /*@Dynamic value:*/ ++ ++ /*@--------- POINTER REFERENCE-----------*/ ++ ODM_CMNINFO_TX_UNI, ++ ODM_CMNINFO_RX_UNI, ++ ODM_CMNINFO_BAND, ++ ODM_CMNINFO_SEC_CHNL_OFFSET, ++ ODM_CMNINFO_SEC_MODE, ++ ODM_CMNINFO_BW, ++ ODM_CMNINFO_CHNL, ++ ODM_CMNINFO_FORCED_RATE, ++ ODM_CMNINFO_ANT_DIV, ++ ODM_CMNINFO_PATH_DIV, ++ ODM_CMNINFO_ADAPTIVE_SOML, ++ ODM_CMNINFO_ADAPTIVITY, ++ ODM_CMNINFO_SCAN, ++ ODM_CMNINFO_POWER_SAVING, ++ ODM_CMNINFO_ONE_PATH_CCA, ++ ODM_CMNINFO_DRV_STOP, ++ ODM_CMNINFO_PNP_IN, ++ ODM_CMNINFO_INIT_ON, ++ ODM_CMNINFO_ANT_TEST, ++ ODM_CMNINFO_NET_CLOSED, ++ ODM_CMNINFO_P2P_LINK, ++ ODM_CMNINFO_FCS_MODE, ++ ODM_CMNINFO_IS1ANTENNA, ++ ODM_CMNINFO_RFDEFAULTPATH, ++ ODM_CMNINFO_DFS_MASTER_ENABLE, ++ ODM_CMNINFO_FORCE_TX_ANT_BY_TXDESC, ++ ODM_CMNINFO_SET_S0S1_DEFAULT_ANTENNA, ++ ODM_CMNINFO_SOFT_AP_MODE, ++ ODM_CMNINFO_MP_MODE, ++ ODM_CMNINFO_INTERRUPT_MASK, ++ ODM_CMNINFO_BB_OPERATION_MODE, ++ ODM_CMNINFO_BF_ANTDIV_DECISION, ++ /*@--------- POINTER REFERENCE-----------*/ ++ ++ /*@------------CALL BY VALUE-------------*/ ++ ODM_CMNINFO_WIFI_DIRECT, ++ ODM_CMNINFO_WIFI_DISPLAY, ++ ODM_CMNINFO_LINK_IN_PROGRESS, ++ ODM_CMNINFO_LINK, ++ ODM_CMNINFO_CMW500LINK, ++ ODM_CMNINFO_STATION_STATE, ++ ODM_CMNINFO_RSSI_MIN, ++ ODM_CMNINFO_RSSI_MIN_BY_PATH, ++ ODM_CMNINFO_DBG_COMP, ++ ODM_CMNINFO_RA_THRESHOLD_HIGH, /*to be removed*/ ++ ODM_CMNINFO_RA_THRESHOLD_LOW, /*to be removed*/ ++ ODM_CMNINFO_RF_ANTENNA_TYPE, ++ ODM_CMNINFO_WITH_EXT_ANTENNA_SWITCH, ++ ODM_CMNINFO_BE_FIX_TX_ANT, ++ ODM_CMNINFO_BT_ENABLED, ++ ODM_CMNINFO_BT_HS_CONNECT_PROCESS, ++ ODM_CMNINFO_BT_HS_RSSI, ++ ODM_CMNINFO_BT_OPERATION, ++ ODM_CMNINFO_BT_LIMITED_DIG, ++ ODM_CMNINFO_AP_TOTAL_NUM, ++ ODM_CMNINFO_POWER_TRAINING, ++ ODM_CMNINFO_DFS_REGION_DOMAIN, ++ ODM_CMNINFO_BT_CONTINUOUS_TURN, ++ /*@------------CALL BY VALUE-------------*/ ++ ++ /*@Dynamic ptr array hook itms.*/ ++ ODM_CMNINFO_STA_STATUS, ++ ODM_CMNINFO_MAX, ++ ++}; ++ ++enum phydm_rfe_bb_source_sel { ++ PAPE_2G = 0, ++ PAPE_5G = 1, ++ LNA0N_2G = 2, ++ LNAON_5G = 3, ++ TRSW = 4, ++ TRSW_B = 5, ++ GNT_BT = 6, ++ ZERO = 7, ++ ANTSEL_0 = 8, ++ ANTSEL_1 = 9, ++ ANTSEL_2 = 0xa, ++ ANTSEL_3 = 0xb, ++ ANTSEL_4 = 0xc, ++ ANTSEL_5 = 0xd, ++ ANTSEL_6 = 0xe, ++ ANTSEL_7 = 0xf ++}; ++ ++enum phydm_info_query { ++ PHYDM_INFO_FA_OFDM, ++ PHYDM_INFO_FA_CCK, ++ PHYDM_INFO_FA_TOTAL, ++ PHYDM_INFO_CCA_OFDM, ++ PHYDM_INFO_CCA_CCK, ++ PHYDM_INFO_CCA_ALL, ++ PHYDM_INFO_CRC32_OK_VHT, ++ PHYDM_INFO_CRC32_OK_HT, ++ PHYDM_INFO_CRC32_OK_LEGACY, ++ PHYDM_INFO_CRC32_OK_CCK, ++ PHYDM_INFO_CRC32_ERROR_VHT, ++ PHYDM_INFO_CRC32_ERROR_HT, ++ PHYDM_INFO_CRC32_ERROR_LEGACY, ++ PHYDM_INFO_CRC32_ERROR_CCK, ++ PHYDM_INFO_EDCCA_FLAG, ++ PHYDM_INFO_OFDM_ENABLE, ++ PHYDM_INFO_CCK_ENABLE, ++ PHYDM_INFO_CRC32_OK_HT_AGG, ++ PHYDM_INFO_CRC32_ERROR_HT_AGG, ++ PHYDM_INFO_DBG_PORT_0, ++ PHYDM_INFO_CURR_IGI, ++ PHYDM_INFO_RSSI_MIN, ++ PHYDM_INFO_RSSI_MAX, ++ PHYDM_INFO_CLM_RATIO, ++ PHYDM_INFO_NHM_RATIO, ++}; ++ ++enum phydm_api { ++ PHYDM_API_NBI = 1, ++ PHYDM_API_CSI_MASK = 2, ++}; ++ ++enum phydm_func_idx { /*@F_XXX = PHYDM XXX function*/ ++ ++ F00_DIG = 0, ++ F01_RA_MASK = 1, ++ F02_DYN_TXPWR = 2, ++ F03_FA_CNT = 3, ++ F04_RSSI_MNTR = 4, ++ F05_CCK_PD = 5, ++ F06_ANT_DIV = 6, ++ F07_SMT_ANT = 7, ++ F08_PWR_TRAIN = 8, ++ F09_RA = 9, ++ F10_PATH_DIV = 10, ++ F11_DFS = 11, ++ F12_DYN_ARFR = 12, ++ F13_ADPTVTY = 13, ++ F14_CFO_TRK = 14, ++ F15_ENV_MNTR = 15, ++ F16_PRI_CCA = 16, ++ F17_ADPTV_SOML = 17, ++ F18_LNA_SAT_CHK = 18, ++}; ++ ++/*@=[PHYDM supportability]==========================================*/ ++enum odm_ability { ++ ODM_BB_DIG = BIT(F00_DIG), ++ ODM_BB_RA_MASK = BIT(F01_RA_MASK), ++ ODM_BB_DYNAMIC_TXPWR = BIT(F02_DYN_TXPWR), ++ ODM_BB_FA_CNT = BIT(F03_FA_CNT), ++ ODM_BB_RSSI_MONITOR = BIT(F04_RSSI_MNTR), ++ ODM_BB_CCK_PD = BIT(F05_CCK_PD), ++ ODM_BB_ANT_DIV = BIT(F06_ANT_DIV), ++ ODM_BB_SMT_ANT = BIT(F07_SMT_ANT), ++ ODM_BB_PWR_TRAIN = BIT(F08_PWR_TRAIN), ++ ODM_BB_RATE_ADAPTIVE = BIT(F09_RA), ++ ODM_BB_PATH_DIV = BIT(F10_PATH_DIV), ++ ODM_BB_DFS = BIT(F11_DFS), ++ ODM_BB_DYNAMIC_ARFR = BIT(F12_DYN_ARFR), ++ ODM_BB_ADAPTIVITY = BIT(F13_ADPTVTY), ++ ODM_BB_CFO_TRACKING = BIT(F14_CFO_TRK), ++ ODM_BB_ENV_MONITOR = BIT(F15_ENV_MNTR), ++ ODM_BB_PRIMARY_CCA = BIT(F16_PRI_CCA), ++ ODM_BB_ADAPTIVE_SOML = BIT(F17_ADPTV_SOML), ++ ODM_BB_LNA_SAT_CHK = BIT(F18_LNA_SAT_CHK), ++}; ++ ++/*@=[PHYDM Debug Component]=====================================*/ ++enum phydm_dbg_comp { ++ /*@BB Driver Functions*/ ++ DBG_DIG = BIT(F00_DIG), ++ DBG_RA_MASK = BIT(F01_RA_MASK), ++ DBG_DYN_TXPWR = BIT(F02_DYN_TXPWR), ++ DBG_FA_CNT = BIT(F03_FA_CNT), ++ DBG_RSSI_MNTR = BIT(F04_RSSI_MNTR), ++ DBG_CCKPD = BIT(F05_CCK_PD), ++ DBG_ANT_DIV = BIT(F06_ANT_DIV), ++ DBG_SMT_ANT = BIT(F07_SMT_ANT), ++ DBG_PWR_TRAIN = BIT(F08_PWR_TRAIN), ++ DBG_RA = BIT(F09_RA), ++ DBG_PATH_DIV = BIT(F10_PATH_DIV), ++ DBG_DFS = BIT(F11_DFS), ++ DBG_DYN_ARFR = BIT(F12_DYN_ARFR), ++ DBG_ADPTVTY = BIT(F13_ADPTVTY), ++ DBG_CFO_TRK = BIT(F14_CFO_TRK), ++ DBG_ENV_MNTR = BIT(F15_ENV_MNTR), ++ DBG_PRI_CCA = BIT(F16_PRI_CCA), ++ DBG_ADPTV_SOML = BIT(F17_ADPTV_SOML), ++ DBG_LNA_SAT_CHK = BIT(F18_LNA_SAT_CHK), ++ /*BIT(19)*/ ++ /*Neet to re-arrange*/ ++ DBG_PHY_STATUS = BIT(20), ++ DBG_TMP = BIT(21), ++ DBG_FW_TRACE = BIT(22), ++ DBG_TXBF = BIT(23), ++ DBG_COMMON_FLOW = BIT(24), ++ DBG_COMP_MCC = BIT(25), ++ /*BIT(26)*/ ++ DBG_DM_SUMMARY = BIT(27), ++ ODM_PHY_CONFIG = BIT(28), ++ ODM_COMP_INIT = BIT(29), ++ DBG_CMN = BIT(30),/*@common*/ ++ ODM_COMP_API = BIT(31) ++}; ++ ++/*@=========================================================*/ ++ ++/*@ODM_CMNINFO_ONE_PATH_CCA*/ ++enum odm_cca_path { ++ ODM_CCA_2R = 0, ++ ODM_CCA_1R_A = 1, ++ ODM_CCA_1R_B = 2, ++}; ++ ++enum phy_reg_pg_type { ++ PHY_REG_PG_RELATIVE_VALUE = 0, ++ PHY_REG_PG_EXACT_VALUE = 1 ++}; ++ ++enum phydm_offload_ability { ++ PHYDM_PHY_PARAM_OFFLOAD = BIT(0), ++ PHYDM_RF_IQK_OFFLOAD = BIT(1), ++}; ++ ++struct phydm_pause_lv { ++ s8 lv_dig; ++ s8 lv_cckpd; ++ s8 lv_antdiv; ++ s8 lv_adapt; ++ s8 lv_adsl; ++}; ++ ++struct phydm_func_poiner { ++ void (*pause_phydm_handler)(void *dm_void, u32 *val_buf, u8 val_len); ++}; ++ ++struct pkt_process_info { ++ u8 phystatus_smp_mode_en; /*@send phystatus every sampling time*/ ++ u8 pre_ppdu_cnt; ++ u8 lna_idx; ++ u8 vga_idx; ++}; ++ ++#ifdef ODM_CONFIG_BT_COEXIST ++struct phydm_bt_info { ++ boolean is_bt_enabled; /*@BT is enabled*/ ++ boolean is_bt_connect_process; /*@BT HS is under connection progress.*/ ++ u8 bt_hs_rssi; /*@BT HS mode wifi rssi value.*/ ++ boolean is_bt_hs_operation; /*@BT HS mode is under progress*/ ++ boolean is_bt_limited_dig; /*@BT is busy.*/ ++}; ++#endif ++ ++struct phydm_iot_center { ++ boolean is_linked_cmw500; ++ u8 win_patch_id; /*@Customer ID*/ ++ u32 phydm_patch_id; ++ ++}; ++ ++#if (RTL8822B_SUPPORT == 1) ++struct drp_rtl8822b_struct { ++ enum bb_path path_judge; ++ u16 path_a_cck_fa; ++ u16 path_b_cck_fa; ++}; ++#endif ++ ++#ifdef CONFIG_MCC_DM ++#define MCC_DM_REG_NUM 32 ++struct _phydm_mcc_dm_ { ++ u8 mcc_pre_status; ++ u8 mcc_reg_id[MCC_DM_REG_NUM]; ++ u16 mcc_dm_reg[MCC_DM_REG_NUM]; ++ u8 mcc_dm_val[MCC_DM_REG_NUM][2]; ++ /*mcc DIG*/ ++ u8 mcc_rssi[2]; ++ /*u8 mcc_igi[2];*/ ++ ++ /* need to be config by driver*/ ++ u8 mcc_status; ++ u8 sta_macid[2][NUM_STA]; ++ u16 mcc_rf_channel[2]; ++ ++}; ++#endif ++ ++ ++#if (DM_ODM_SUPPORT_TYPE & ODM_WIN) ++ #if (RT_PLATFORM != PLATFORM_LINUX) ++ typedef ++ #endif ++ ++struct dm_struct { ++#else/*for AP, CE Team*/ ++struct dm_struct { ++#endif ++ /*@Add for different team use temporarily*/ ++ void *adapter; /*@For CE/NIC team*/ ++ struct rtl8192cd_priv *priv; /*@For AP team*/ ++ boolean odm_ready; ++ enum phy_reg_pg_type phy_reg_pg_value_type; ++ u8 phy_reg_pg_version; ++ u64 support_ability; /*@PHYDM function Supportability*/ ++ u64 pause_ability; /*@PHYDM function pause Supportability*/ ++ u64 debug_components; ++ u8 cmn_dbg_msg_period; ++ u8 cmn_dbg_msg_cnt; ++ u32 fw_debug_components; ++ u32 num_qry_phy_status_all; /*@CCK + OFDM*/ ++ u32 last_num_qry_phy_status_all; ++ u32 rx_pwdb_ave; ++ boolean is_init_hw_info_by_rfe; ++ ++ /*@------ ODM HANDLE, DRIVER NEEDS NOT TO HOOK------*/ ++ boolean is_cck_high_power; ++ u8 rf_path_rx_enable; ++ /*@------ ODM HANDLE, DRIVER NEEDS NOT TO HOOK------*/ ++ ++ /* @COMMON INFORMATION */ ++ ++ /*@Init value*/ ++ /*@-----------HOOK BEFORE REG INIT-----------*/ ++ ++ u8 support_platform; /*@PHYDM Platform info WIN/AP/CE = 1/2/3 */ ++ u8 normal_rx_path; ++ boolean brxagcswitch; /* @for rx AGC table switch in Microsoft case */ ++ u8 support_interface; /*@PHYDM PCIE/USB/SDIO = 1/2/3*/ ++ u32 support_ic_type; /*@PHYDM supported IC*/ ++ u8 ic_ip_series; /*N/AC/JGR3*/ ++ enum phydm_phy_sts_type ic_phy_sts_type; /*@Type1/type2/type3*/ ++ u8 cut_version; /*@cut version TestChip/A-cut/B-cut... = 0/1/2/3/...*/ ++ u8 fab_version; /*@Fab version TSMC/UMC = 0/1*/ ++ u8 fw_version; ++ u8 fw_sub_version; ++ u8 rf_type; /*@RF type 4T4R/3T3R/2T2R/1T2R/1T1R/...*/ ++ u8 rfe_type; ++ u8 board_type; ++ u8 package_type; ++ u16 type_glna; ++ u16 type_gpa; ++ u16 type_alna; ++ u16 type_apa; ++ u8 ext_lna; /*@with 2G external LNA NO/Yes = 0/1*/ ++ u8 ext_lna_5g; /*@with 5G external LNA NO/Yes = 0/1*/ ++ u8 ext_pa; /*@with 2G external PNA NO/Yes = 0/1*/ ++ u8 ext_pa_5g; /*@with 5G external PNA NO/Yes = 0/1*/ ++ u8 efuse0x3d7; /*@with Efuse number*/ ++ u8 efuse0x3d8; ++ u8 ext_trsw; /*@with external TRSW NO/Yes = 0/1*/ ++ u8 ext_lna_gain; /*@gain of external lna*/ ++ boolean is_in_hct_test; ++ u8 wifi_test; ++ boolean is_dual_mac_smart_concurrent; ++ u32 bk_support_ability; /*SD4 only*/ ++ u8 with_extenal_ant_switch; ++ /*@cck agc relative*/ ++ boolean cck_new_agc; ++ s8 cck_lna_gain_table[8]; ++ /*@-------------------------------------*/ ++ u32 phydm_sys_up_time; ++ u8 num_rf_path; /*@ex: 8821C=1, 8192E=2, 8814B=4*/ ++ u32 soft_ap_special_setting; ++ s8 s8_dummy; ++ u8 u8_dummy; ++ u16 u16_dummy; ++ u32 u32_dummy; ++ u8 rfe_hwsetting_band; ++ u8 p_advance_ota; ++ boolean hp_hw_id; ++ boolean BOOLEAN_temp; ++ boolean is_dfs_band; ++ u8 is_rx_blocking_en; ++ u16 fw_offload_ability; ++/*@-----------HOOK BEFORE REG INIT-----------*/ ++/*@===========================================================*/ ++/*@====[ CALL BY Reference ]=========================================*/ ++/*@===========================================================*/ ++ ++ u64 *num_tx_bytes_unicast; /*@TX Unicast byte cnt*/ ++ u64 *num_rx_bytes_unicast; /*@RX Unicast byte cnt*/ ++ u8 *band_type; /*@2.4G/5G = 0/1*/ ++ u8 *sec_ch_offset; /*@Secondary channel offset don't_care/below/above = 0/1/2*/ ++ u8 *security; /*@security mode Open/WEP/AES/TKIP = 0/1/2/3*/ ++ u8 *band_width; /*@20M/40M/80M = 0/1/2*/ ++ u8 *channel; /*@central CH number*/ ++ boolean *is_scan_in_process; ++ boolean *is_power_saving; ++ boolean *is_tdma; ++ u8 *one_path_cca; /*@CCA path 2-path/path-A/path-B = 0/1/2; using enum odm_cca_path.*/ ++ u8 *antenna_test; ++ boolean *is_net_closed; ++ boolean *is_fcs_mode_enable; ++ /*@--------- For 8723B IQK-------------------------------------*/ ++ boolean *is_1_antenna; ++ u8 *rf_default_path; /* @0:S1, 1:S0 */ ++ /*@-----------------------------------------------------------*/ ++ ++ u16 *forced_data_rate; ++ u8 *enable_antdiv; ++ u8 *enable_pathdiv; ++ u8 *en_adap_soml; ++ u8 *enable_adaptivity; ++ u8 *hub_usb_mode; /*@1:USB2.0, 2:USB3.0*/ ++ boolean *is_fw_dw_rsvd_page_in_progress; ++ u32 *current_tx_tp; ++ u32 *current_rx_tp; ++ u8 *sounding_seq; ++ u32 *soft_ap_mode; ++ u8 *mp_mode; ++ u32 *interrupt_mask; ++ u8 *bb_op_mode; ++/*@===========================================================*/ ++/*@====[ CALL BY VALUE ]===========================================*/ ++/*@===========================================================*/ ++ ++ u8 disable_phydm_watchdog; ++ boolean is_link_in_process; ++ boolean is_wifi_direct; ++ boolean is_wifi_display; ++ boolean is_linked; ++ boolean bsta_state; ++ u8 rssi_min; ++ u8 rssi_min_macid; ++ u8 pre_rssi_min; ++ u8 rssi_max; ++ u8 rssi_max_macid; ++ u8 rssi_min_by_path; ++ boolean is_one_entry_only; ++ u32 one_entry_macid; ++ u32 one_entry_tp; ++ u32 pre_one_entry_tp; ++ u8 pre_number_linked_client; ++ u8 number_linked_client; ++ u8 pre_number_active_client; ++ u8 number_active_client; ++ boolean is_disable_phy_api; ++ u8 rssi_a; ++ u8 rssi_b; ++ u8 rssi_c; ++ u8 rssi_d; ++ s8 rxsc_80; ++ s8 rxsc_40; ++ s8 rxsc_20; ++ s8 rxsc_l; ++ u64 rssi_trsw; ++ u64 rssi_trsw_h; ++ u64 rssi_trsw_l; ++ u64 rssi_trsw_iso; ++ u8 tx_ant_status; ++ u8 rx_ant_status; ++ u8 cck_lna_idx; ++ u8 cck_vga_idx; ++ u8 curr_station_id; ++ u8 ofdm_agc_idx[4]; ++ u8 rx_rate; ++ u8 rate_ss; ++ u8 tx_rate; ++ u8 linked_interval; ++ u8 pre_channel; ++ u32 txagc_offset_value_a; ++ boolean is_txagc_offset_positive_a; ++ u32 txagc_offset_value_b; ++ boolean is_txagc_offset_positive_b; ++ u8 ap_total_num; ++ /*@[traffic]*/ ++ u8 traffic_load; ++ u8 pre_traffic_load; ++ u32 tx_tp; /*@Mbps*/ ++ u32 rx_tp; /*@Mbps*/ ++ u32 total_tp; /*@Mbps*/ ++ u8 txrx_state_all; /*@0:tx, 1:rx, 2:bi-dir*/ ++ u64 cur_tx_ok_cnt; ++ u64 cur_rx_ok_cnt; ++ u64 last_tx_ok_cnt; ++ u64 last_rx_ok_cnt; ++ u16 consecutive_idlel_time; /*@unit: second*/ ++ /*@---------------------------*/ ++ boolean is_bb_swing_offset_positive_a; ++ boolean is_bb_swing_offset_positive_b; ++ ++ /*@[DIG]*/ ++ boolean MPDIG_2G; /*off MPDIG*/ ++ u8 times_2g; /*@for MP DIG*/ ++ u8 force_igi; /*@for debug*/ ++ ++ /*@[TDMA-DIG]*/ ++ u8 tdma_dig_timer_ms; ++ u8 tdma_dig_state_number; ++ u8 tdma_dig_low_upper_bond; ++ u8 force_tdma_low_igi; ++ u8 force_tdma_high_igi; ++ u8 fix_expire_to_zero; ++ boolean original_dig_restore; ++ /*@---------------------------*/ ++ ++ /*@[AntDiv]*/ ++ u8 ant_div_type; ++ u8 antdiv_rssi; ++ u8 fat_comb_a; ++ u8 fat_comb_b; ++ u8 antdiv_intvl; ++ u8 ant_type; ++ u8 ant_type2; ++ u8 pre_ant_type; ++ u8 pre_ant_type2; ++ u8 antdiv_period; ++ u8 evm_antdiv_period; ++ u8 antdiv_select; ++ u8 antdiv_train_num; /*@training time for each antenna in EVM method*/ ++ u8 stop_antdiv_rssi_th; ++ u16 stop_antdiv_tp_diff_th; ++ u16 stop_antdiv_tp_th; ++ u8 antdiv_tp_period; ++ u16 tp_active_th; ++ u8 tp_active_occur; ++ u8 path_select; ++ u8 antdiv_evm_en; ++ u8 bdc_holdstate; ++ u8 antdiv_counter; ++ /*@---------------------------*/ ++ ++ u8 ndpa_period; ++ boolean h2c_rarpt_connect; ++ boolean cck_agc_report_type; /*@1:4bit LNA, 0:3bit LNA */ ++ u8 print_agc; ++ u8 la_mode; ++ /*@---8821C Antenna and RF Set BTG/WLG/WLA Select---------------*/ ++ u8 current_rf_set_8821c; ++ u8 default_rf_set_8821c; ++ u8 current_ant_num_8821c; ++ u8 default_ant_num_8821c; ++ u8 rfe_type_expand; ++ /*@-----------------------------------------------------------*/ ++ /*@---For Adaptivtiy---------------------------------------------*/ ++ s8 TH_L2H_default; ++ s8 th_edcca_hl_diff_default; ++ s8 th_l2h_ini; ++ s8 th_edcca_hl_diff; ++ boolean carrier_sense_enable; ++ /*@-----------------------------------------------------------*/ ++ ++ u8 pre_dbg_priority; ++ u8 nbi_set_result; ++ u8 c2h_cmd_start; ++ u8 fw_debug_trace[60]; ++ u8 pre_c2h_seq; ++ boolean fw_buff_is_enpty; ++ u32 data_frame_num; ++ ++ /*@--- for noise detection ---------------------------------------*/ ++ boolean is_noisy_state; ++ boolean noisy_decision; /*@b_noisy*/ ++ boolean pre_b_noisy; ++ u32 noisy_decision_smooth; ++ /*@-----------------------------------------------------------*/ ++ ++ /*@--- for MCC ant weighting ------------------------------------*/ ++ boolean is_stop_dym_ant_weighting; ++ /*@-----------------------------------------------------------*/ ++ ++ boolean is_disable_dym_ecs; ++ boolean is_disable_dym_ant_weighting; ++ struct cmn_sta_info *phydm_sta_info[ODM_ASSOCIATE_ENTRY_NUM]; ++ u8 phydm_macid_table[ODM_ASSOCIATE_ENTRY_NUM];/*@sta_idx = phydm_macid_table[HW_macid]*/ ++ ++#if (RATE_ADAPTIVE_SUPPORT == 1) ++ u16 currmin_rpt_time; ++ struct _phydm_txstatistic_ hw_stats; ++ struct _odm_ra_info_ ra_info[ODM_ASSOCIATE_ENTRY_NUM]; ++/*Use mac_id as array index. STA mac_id=0*/ ++/*VWiFi Client mac_id={1, ODM_ASSOCIATE_ENTRY_NUM-1} //YJ,add,120119*/ ++#endif ++ /*@2012/02/14 MH Add to share 88E ra with other SW team*/ ++ /*We need to colelct all support abilit to a proper area.*/ ++ boolean ra_support88e; ++ boolean *is_driver_stopped; ++ boolean *is_driver_is_going_to_pnp_set_power_sleep; ++ boolean *pinit_adpt_in_progress; ++ boolean is_user_assign_level; ++ u8 RSSI_BT; /*@come from BT*/ ++ ++ /*@---PSD Relative ---------------------------------------------*/ ++ boolean is_psd_in_process; ++ boolean is_psd_active; ++ /*@-----------------------------------------------------------*/ ++ ++ boolean bsomlenabled; /* @D-SoML control */ ++ boolean bhtstfdisabled; /* @dynamic HTSTF gain control*/ ++ u32 n_iqk_cnt; ++ u32 n_iqk_ok_cnt; ++ u32 n_iqk_fail_cnt; ++ ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ boolean config_bbrf; ++#endif ++ boolean is_disable_power_training; ++ boolean is_bt_continuous_turn; ++ u8 enhance_pwr_th[3]; ++ u8 set_pwr_th[3]; ++ /*@----------Dyn Tx Pwr ---------------------------------------*/ ++#ifdef BB_RAM_SUPPORT ++ struct phydm_bb_ram_ctrl p_bb_ram_ctrl; ++#endif ++ u8 dynamic_tx_high_power_lvl; ++ void (*fill_desc_dyntxpwr)(void *dm, u8 *desc, u8 dyn_tx_power); ++ u8 last_dtp_lvl; ++ u8 min_power_index; ++ u32 tx_agc_ofdm_18_6; ++ /*-------------------------------------------------------------*/ ++ u8 rx_pkt_type; ++ ++#ifdef CONFIG_PHYDM_DFS_MASTER ++ u8 dfs_region_domain; ++ u8 *dfs_master_enabled; ++ /*@---phydm_radar_detect_with_dbg_parm start --------------------*/ ++ u8 radar_detect_dbg_parm_en; ++ u32 radar_detect_reg_918; ++ u32 radar_detect_reg_91c; ++ u32 radar_detect_reg_920; ++ u32 radar_detect_reg_924; ++ u32 radar_detect_reg_f54; ++ u32 radar_detect_reg_f58; ++ u32 radar_detect_reg_f5c; ++ u32 radar_detect_reg_f70; ++ u32 radar_detect_reg_f74; ++/*@-----------------------------------------------------------*/ ++#endif ++ ++/*@=== PHYDM Timer ========================================== (start)*/ ++ ++ struct phydm_timer_list mpt_dig_timer; ++ struct phydm_timer_list fast_ant_training_timer; ++#ifdef ODM_EVM_ENHANCE_ANTDIV ++ struct phydm_timer_list evm_fast_ant_training_timer; ++#endif ++#ifdef PHYDM_TDMA_DIG_SUPPORT ++ struct phydm_timer_list tdma_dig_timer; ++#endif ++ struct phydm_timer_list sbdcnt_timer; ++ ++/*@=== PHYDM Workitem ======================================= (start)*/ ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) ++#if USE_WORKITEM ++ RT_WORK_ITEM fast_ant_training_workitem; ++ RT_WORK_ITEM ra_rpt_workitem; ++ RT_WORK_ITEM sbdcnt_workitem; ++ RT_WORK_ITEM phydm_evm_antdiv_workitem; ++#endif ++#endif ++ ++/*@=== PHYDM Structure ======================================== (start)*/ ++ struct phydm_func_poiner phydm_func_handler; ++ struct phydm_iot_center iot_table; ++ ++#ifdef ODM_CONFIG_BT_COEXIST ++ struct phydm_bt_info bt_info_table; ++#endif ++ ++ struct pkt_process_info pkt_proc_struct; ++ struct phydm_adaptivity_struct adaptivity; ++ struct _DFS_STATISTICS dfs; ++ struct odm_noise_monitor noise_level; ++ struct odm_phy_dbg_info phy_dbg_info; ++ ++#ifdef CONFIG_ADAPTIVE_SOML ++ struct adaptive_soml dm_soml_table; ++#endif ++ ++#if (defined(CONFIG_PHYDM_ANTENNA_DIVERSITY)) ++ #if (DM_ODM_SUPPORT_TYPE & (ODM_AP)) ++ struct _BF_DIV_COEX_ dm_bdc_table; ++ #endif ++ ++ #if (defined(CONFIG_HL_SMART_ANTENNA)) ++ struct smt_ant_honbo dm_sat_table; ++ #endif ++#endif ++ ++#if (defined(CONFIG_SMART_ANTENNA)) ++ struct smt_ant smtant_table; ++#endif ++ ++ struct _hal_rf_ rf_table; /*@for HALRF function*/ ++ struct dm_rf_calibration_struct rf_calibrate_info; ++ struct dm_iqk_info IQK_info; ++ struct dm_dpk_info dpk_info; ++ ++#ifdef CONFIG_PHYDM_ANTENNA_DIVERSITY ++ struct phydm_fat_struct dm_fat_table; ++ struct sw_antenna_switch dm_swat_table; ++#endif ++ struct phydm_dig_struct dm_dig_table; ++#ifdef PHYDM_LNA_SAT_CHK_SUPPORT ++ struct phydm_lna_sat_t dm_lna_sat_info; ++#endif ++ ++#ifdef CONFIG_MCC_DM ++ struct _phydm_mcc_dm_ mcc_dm; ++#endif ++ ++#ifdef PHYDM_SUPPORT_CCKPD ++ struct phydm_cckpd_struct dm_cckpd_table; ++#endif ++ ++#ifdef PHYDM_PRIMARY_CCA ++ struct phydm_pricca_struct dm_pri_cca; ++#endif ++ ++ struct ra_table dm_ra_table; ++ struct phydm_fa_struct false_alm_cnt; ++#ifdef PHYDM_TDMA_DIG_SUPPORT ++ struct phydm_fa_acc_struct false_alm_cnt_acc; ++#ifdef IS_USE_NEW_TDMA ++ struct phydm_fa_acc_struct false_alm_cnt_acc_low; ++#endif ++#endif ++ struct phydm_cfo_track_struct dm_cfo_track; ++ struct ccx_info dm_ccx_info; ++ ++ struct odm_power_trim_data power_trim_data; ++#if (RTL8822B_SUPPORT == 1) ++ struct drp_rtl8822b_struct phydm_rtl8822b; ++#endif ++ ++#ifdef CONFIG_PSD_TOOL ++ struct psd_info dm_psd_table; ++#endif ++ ++#if (PHYDM_LA_MODE_SUPPORT == 1) ++ struct rt_adcsmp adcsmp; ++#endif ++ ++#if (defined(CONFIG_PATH_DIVERSITY)) ++ struct _ODM_PATH_DIVERSITY_ dm_path_div; ++#endif ++ ++#if (defined(CONFIG_ANT_DETECTION)) ++ struct _ANT_DETECTED_INFO ant_detected_info; ++#endif ++ ++#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE)) ++#ifdef PHYDM_BEAMFORMING_SUPPORT ++ struct _RT_BEAMFORMING_INFO beamforming_info; ++#endif ++#endif ++#ifdef PHYDM_AUTO_DEGBUG ++ struct phydm_auto_dbg_struct auto_dbg_table; ++#endif ++ ++ struct phydm_pause_lv pause_lv_table; ++ struct phydm_api_stuc api_table; ++#ifdef PHYDM_POWER_TRAINING_SUPPORT ++ struct phydm_pow_train_stuc pow_train_table; ++#endif ++ ++#ifdef PHYDM_PMAC_TX_SETTING_SUPPORT ++ struct phydm_pmac_tx dm_pmac_tx_table; ++#endif ++ ++#ifdef PHYDM_MP_SUPPORT ++ struct phydm_mp dm_mp_table; ++#endif ++/*@==========================================================*/ ++ ++#if (DM_ODM_SUPPORT_TYPE & ODM_WIN) ++ ++#if (RT_PLATFORM != PLATFORM_LINUX) ++} dm_struct; /*@DM_Dynamic_Mechanism_Structure*/ ++#else ++}; ++#endif ++ ++#else /*@for AP,CE Team*/ ++}; ++#endif ++ ++enum phydm_adv_ota { ++ PHYDM_PATHB_1RCCA = BIT(0), ++ PHYDM_HP_OTA_SETTING_A = BIT(1), ++ PHYDM_HP_OTA_SETTING_B = BIT(2), ++ PHYDM_ASUS_OTA_SETTING = BIT(3), ++ PHYDM_ASUS_OTA_SETTING_CCK_PATH = BIT(4), ++ PHYDM_HP_OTA_SETTING_CCK_PATH = BIT(5), ++ PHYDM_LENOVO_OTA_SETTING_NBI_CSI = BIT(6), ++ ++}; ++ ++enum phydm_bb_op_mode { ++ PHYDM_PERFORMANCE_MODE = 0, /*Service one device*/ ++ PHYDM_BALANCE_MODE = 1, /*@Service more than one device*/ ++}; ++ ++enum phydm_structure_type { ++ PHYDM_FALSEALMCNT, ++ PHYDM_CFOTRACK, ++ PHYDM_ADAPTIVITY, ++ PHYDM_DFS, ++ PHYDM_ROMINFO, ++ ++}; ++ ++enum odm_bb_config_type { ++ CONFIG_BB_PHY_REG, ++ CONFIG_BB_AGC_TAB, ++ CONFIG_BB_AGC_TAB_2G, ++ CONFIG_BB_AGC_TAB_5G, ++ CONFIG_BB_PHY_REG_PG, ++ CONFIG_BB_PHY_REG_MP, ++ CONFIG_BB_AGC_TAB_DIFF, ++ CONFIG_BB_RF_CAL_INIT, ++}; ++ ++enum odm_rf_config_type { ++ CONFIG_RF_RADIO, ++ CONFIG_RF_TXPWR_LMT, ++ CONFIG_RF_SYN_RADIO, ++}; ++ ++enum odm_fw_config_type { ++ CONFIG_FW_NIC, ++ CONFIG_FW_NIC_2, ++ CONFIG_FW_AP, ++ CONFIG_FW_AP_2, ++ CONFIG_FW_MP, ++ CONFIG_FW_WOWLAN, ++ CONFIG_FW_WOWLAN_2, ++ CONFIG_FW_AP_WOWLAN, ++ CONFIG_FW_BT, ++}; ++ ++/*status code*/ ++#if (DM_ODM_SUPPORT_TYPE != ODM_WIN) ++enum rt_status { ++ RT_STATUS_SUCCESS, ++ RT_STATUS_FAILURE, ++ RT_STATUS_PENDING, ++ RT_STATUS_RESOURCE, ++ RT_STATUS_INVALID_CONTEXT, ++ RT_STATUS_INVALID_PARAMETER, ++ RT_STATUS_NOT_SUPPORT, ++ RT_STATUS_OS_API_FAILED, ++}; ++#endif /*@end of enum rt_status definition*/ ++ ++void ++phydm_watchdog_lps(struct dm_struct *dm); ++ ++void ++phydm_watchdog_lps_32k(struct dm_struct *dm); ++ ++void ++phydm_txcurrentcalibration(struct dm_struct *dm); ++ ++void ++phydm_dm_early_init(struct dm_struct *dm); ++ ++void ++odm_dm_init(struct dm_struct *dm); ++ ++void ++odm_dm_reset(struct dm_struct *dm); ++ ++void ++phydm_fwoffload_ability_init(struct dm_struct *dm, ++ enum phydm_offload_ability offload_ability); ++ ++void ++phydm_fwoffload_ability_clear(struct dm_struct *dm, ++ enum phydm_offload_ability offload_ability); ++ ++void ++phydm_supportability_en(void *dm_void, char input[][16], u32 *_used, ++ char *output, u32 *_out_len); ++ ++void ++phydm_pause_dm_watchdog(void *dm_void, enum phydm_pause_type pause_type); ++ ++void ++phydm_watchdog(struct dm_struct *dm); ++ ++void ++phydm_watchdog_mp(struct dm_struct *dm); ++ ++u8 ++phydm_pause_func(void *dm_void, enum phydm_func_idx pause_func, ++ enum phydm_pause_type pause_type, ++ enum phydm_pause_level pause_lv, u8 val_lehgth, u32 *val_buf); ++ ++void ++phydm_pause_func_console(void *dm_void, char input[][16], u32 *_used, ++ char *output, u32 *_out_len); ++ ++void ++odm_cmn_info_init(struct dm_struct *dm, enum odm_cmninfo cmn_info, u64 value); ++ ++void ++odm_cmn_info_hook(struct dm_struct *dm, enum odm_cmninfo cmn_info, void *value); ++ ++void ++odm_cmn_info_update(struct dm_struct *dm, u32 cmn_info, u64 value); ++ ++u32 ++phydm_cmn_info_query(struct dm_struct *dm, enum phydm_info_query info_type); ++ ++void ++odm_init_all_timers(struct dm_struct *dm); ++ ++void ++odm_cancel_all_timers(struct dm_struct *dm); ++ ++void ++odm_release_all_timers(struct dm_struct *dm); ++ ++void * ++phydm_get_structure(struct dm_struct *dm, u8 structure_type); ++ ++void ++phydm_dc_cancellation(struct dm_struct *dm); ++ ++void ++phydm_receiver_blocking(void *dm_void); ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) ++void ++odm_init_all_work_items( ++ struct dm_struct *dm ++); ++void ++odm_free_all_work_items( ++ struct dm_struct *dm ++); ++#endif /*@#if (DM_ODM_SUPPORT_TYPE == ODM_WIN)*/ ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++void ++odm_dtc(struct dm_struct *dm); ++#endif ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_AP) ++void ++odm_init_all_threads( ++ struct dm_struct *dm ++); ++ ++void ++odm_stop_all_threads( ++ struct dm_struct *dm ++); ++#endif ++ ++#endif +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_hwconfig.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_hwconfig.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_hwconfig.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_hwconfig.c 2021-03-07 18:16:17.063956478 +0200 @@ -0,0 +1,1419 @@ +/****************************************************************************** + * @@ -239326,11 +235964,9 @@ index 000000000..4c4d9386e +#endif + return value32; +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_hwconfig.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_hwconfig.h -new file mode 100644 -index 000000000..7c4d1e38c ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_hwconfig.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_hwconfig.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_hwconfig.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_hwconfig.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_hwconfig.h 2021-03-07 18:16:17.063956478 +0200 @@ -0,0 +1,79 @@ +/****************************************************************************** + * @@ -239411,11 +236047,9 @@ index 000000000..7c4d1e38c +u32 query_phydm_txbf_capability(struct dm_struct *dm); + +#endif /*@#ifndef __HALHWOUTSRC_H__*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_interface.c linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_interface.c -new file mode 100644 -index 000000000..fe0f5c220 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_interface.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_interface.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_interface.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_interface.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_interface.c 2021-03-07 18:16:17.063956478 +0200 @@ -0,0 +1,1468 @@ +/****************************************************************************** + * @@ -240885,11 +237519,9 @@ index 000000000..fe0f5c220 + return tx_rate; +} + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_interface.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_interface.h -new file mode 100644 -index 000000000..38edfb498 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_interface.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_interface.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_interface.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_interface.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_interface.h 2021-03-07 18:16:17.063956478 +0200 @@ -0,0 +1,343 @@ +/****************************************************************************** + * @@ -241234,11 +237866,9 @@ index 000000000..38edfb498 + void *context); +u32 phydm_get_tx_rate(struct dm_struct *dm); +#endif /* @__ODM_INTERFACE_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_lna_sat.c linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_lna_sat.c -new file mode 100644 -index 000000000..5320468b3 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_lna_sat.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_lna_sat.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_lna_sat.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_lna_sat.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_lna_sat.c 2021-03-07 18:16:17.063956478 +0200 @@ -0,0 +1,1343 @@ +/****************************************************************************** + * @@ -242583,11 +239213,9 @@ index 000000000..5320468b3 +} + +#endif /*@#ifdef PHYDM_LNA_SAT_CHK_SUPPORT*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_lna_sat.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_lna_sat.h -new file mode 100644 -index 000000000..c9345b86f ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_lna_sat.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_lna_sat.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_lna_sat.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_lna_sat.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_lna_sat.h 2021-03-07 18:16:17.063956478 +0200 @@ -0,0 +1,173 @@ +/****************************************************************************** + * @@ -242762,11 +239390,9 @@ index 000000000..c9345b86f + +#endif /*@#if (PHYDM_LNA_SAT_CHK_SUPPORT == 1)*/ +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_math_lib.c linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_math_lib.c -new file mode 100644 -index 000000000..cf1568ca4 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_math_lib.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_math_lib.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_math_lib.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_math_lib.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_math_lib.c 2021-03-07 18:16:17.063956478 +0200 @@ -0,0 +1,248 @@ +/****************************************************************************** + * @@ -243016,11 +239642,9 @@ index 000000000..cf1568ca4 + return val; +} + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_math_lib.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_math_lib.h -new file mode 100644 -index 000000000..daee35207 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_math_lib.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_math_lib.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_math_lib.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_math_lib.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_math_lib.h 2021-03-07 18:16:17.063956478 +0200 @@ -0,0 +1,114 @@ +/****************************************************************************** + * @@ -243136,11 +239760,240 @@ index 000000000..daee35207 + +s32 phydm_cnvrt_2_sign(u32 val, u8 bit_num); +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_mp.c linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_mp.c -new file mode 100644 -index 000000000..7d964f5d6 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_mp.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm.mk linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm.mk +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm.mk 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm.mk 2021-03-07 18:16:17.059956289 +0200 +@@ -0,0 +1,226 @@ ++EXTRA_CFLAGS += -I$(src)/hal/phydm ++ ++_PHYDM_FILES := hal/phydm/phydm_debug.o \ ++ hal/phydm/phydm_antdiv.o\ ++ hal/phydm/phydm_soml.o\ ++ hal/phydm/phydm_smt_ant.o\ ++ hal/phydm/phydm_antdect.o\ ++ hal/phydm/phydm_interface.o\ ++ hal/phydm/phydm_phystatus.o\ ++ hal/phydm/phydm_hwconfig.o\ ++ hal/phydm/phydm.o\ ++ hal/phydm/phydm_dig.o\ ++ hal/phydm/phydm_pathdiv.o\ ++ hal/phydm/phydm_rainfo.o\ ++ hal/phydm/phydm_dynamictxpower.o\ ++ hal/phydm/phydm_adaptivity.o\ ++ hal/phydm/phydm_cfotracking.o\ ++ hal/phydm/phydm_noisemonitor.o\ ++ hal/phydm/phydm_beamforming.o\ ++ hal/phydm/phydm_dfs.o\ ++ hal/phydm/txbf/halcomtxbf.o\ ++ hal/phydm/txbf/haltxbfinterface.o\ ++ hal/phydm/txbf/phydm_hal_txbf_api.o\ ++ hal/phydm/phydm_adc_sampling.o\ ++ hal/phydm/phydm_ccx.o\ ++ hal/phydm/phydm_psd.o\ ++ hal/phydm/phydm_primary_cca.o\ ++ hal/phydm/phydm_cck_pd.o\ ++ hal/phydm/phydm_rssi_monitor.o\ ++ hal/phydm/phydm_auto_dbg.o\ ++ hal/phydm/phydm_math_lib.o\ ++ hal/phydm/phydm_api.o\ ++ hal/phydm/phydm_pow_train.o\ ++ hal/phydm/phydm_lna_sat.o\ ++ hal/phydm/phydm_pmac_tx_setting.o\ ++ hal/phydm/phydm_mp.o\ ++ hal/phydm/halrf/halrf.o\ ++ hal/phydm/halrf/halrf_debug.o\ ++ hal/phydm/halrf/halphyrf_ce.o\ ++ hal/phydm/halrf/halrf_powertracking_ce.o\ ++ hal/phydm/halrf/halrf_powertracking.o\ ++ hal/phydm/halrf/halrf_kfree.o ++ ++ifeq ($(CONFIG_RTL8188E), y) ++RTL871X = rtl8188e ++_PHYDM_FILES += hal/phydm/$(RTL871X)/halhwimg8188e_mac.o\ ++ hal/phydm/$(RTL871X)/halhwimg8188e_bb.o\ ++ hal/phydm/$(RTL871X)/halhwimg8188e_rf.o\ ++ hal/phydm/halrf/$(RTL871X)/halrf_8188e_ce.o\ ++ hal/phydm/$(RTL871X)/phydm_regconfig8188e.o\ ++ hal/phydm/$(RTL871X)/hal8188erateadaptive.o\ ++ hal/phydm/$(RTL871X)/phydm_rtl8188e.o ++endif ++ ++ifeq ($(CONFIG_RTL8192E), y) ++RTL871X = rtl8192e ++_PHYDM_FILES += hal/phydm/$(RTL871X)/halhwimg8192e_mac.o\ ++ hal/phydm/$(RTL871X)/halhwimg8192e_bb.o\ ++ hal/phydm/$(RTL871X)/halhwimg8192e_rf.o\ ++ hal/phydm/halrf/$(RTL871X)/halrf_8192e_ce.o\ ++ hal/phydm/$(RTL871X)/phydm_regconfig8192e.o\ ++ hal/phydm/$(RTL871X)/phydm_rtl8192e.o ++endif ++ ++ ++ifeq ($(CONFIG_RTL8812A), y) ++RTL871X = rtl8812a ++_PHYDM_FILES += hal/phydm/$(RTL871X)/halhwimg8812a_mac.o\ ++ hal/phydm/$(RTL871X)/halhwimg8812a_bb.o\ ++ hal/phydm/$(RTL871X)/halhwimg8812a_rf.o\ ++ hal/phydm/halrf/$(RTL871X)/halrf_8812a_ce.o\ ++ hal/phydm/$(RTL871X)/phydm_regconfig8812a.o\ ++ hal/phydm/$(RTL871X)/phydm_rtl8812a.o\ ++ hal/phydm/txbf/haltxbfjaguar.o ++endif ++ ++ifeq ($(CONFIG_RTL8821A), y) ++RTL871X = rtl8821a ++_PHYDM_FILES += hal/phydm/rtl8821a/halhwimg8821a_mac.o\ ++ hal/phydm/rtl8821a/halhwimg8821a_bb.o\ ++ hal/phydm/rtl8821a/halhwimg8821a_rf.o\ ++ hal/phydm/halrf/rtl8812a/halrf_8812a_ce.o\ ++ hal/phydm/halrf/rtl8821a/halrf_8821a_ce.o\ ++ hal/phydm/rtl8821a/phydm_regconfig8821a.o\ ++ hal/phydm/rtl8821a/phydm_rtl8821a.o\ ++ hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ce.o\ ++ hal/phydm/txbf/haltxbfjaguar.o ++endif ++ ++ ++ifeq ($(CONFIG_RTL8723B), y) ++RTL871X = rtl8723b ++_PHYDM_FILES += hal/phydm/$(RTL871X)/halhwimg8723b_bb.o\ ++ hal/phydm/$(RTL871X)/halhwimg8723b_mac.o\ ++ hal/phydm/$(RTL871X)/halhwimg8723b_rf.o\ ++ hal/phydm/$(RTL871X)/halhwimg8723b_mp.o\ ++ hal/phydm/$(RTL871X)/phydm_regconfig8723b.o\ ++ hal/phydm/halrf/$(RTL871X)/halrf_8723b_ce.o\ ++ hal/phydm/$(RTL871X)/phydm_rtl8723b.o ++endif ++ ++ ++ifeq ($(CONFIG_RTL8814A), y) ++RTL871X = rtl8814a ++_PHYDM_FILES += hal/phydm/$(RTL871X)/halhwimg8814a_bb.o\ ++ hal/phydm/$(RTL871X)/halhwimg8814a_mac.o\ ++ hal/phydm/$(RTL871X)/halhwimg8814a_rf.o\ ++ hal/phydm/halrf/$(RTL871X)/halrf_iqk_8814a.o\ ++ hal/phydm/$(RTL871X)/phydm_regconfig8814a.o\ ++ hal/phydm/halrf/$(RTL871X)/halrf_8814a_ce.o\ ++ hal/phydm/$(RTL871X)/phydm_rtl8814a.o\ ++ hal/phydm/txbf/haltxbf8814a.o ++endif ++ ++ ++ifeq ($(CONFIG_RTL8723C), y) ++RTL871X = rtl8703b ++_PHYDM_FILES += hal/phydm/$(RTL871X)/halhwimg8703b_bb.o\ ++ hal/phydm/$(RTL871X)/halhwimg8703b_mac.o\ ++ hal/phydm/$(RTL871X)/halhwimg8703b_rf.o\ ++ hal/phydm/$(RTL871X)/phydm_regconfig8703b.o\ ++ hal/phydm/$(RTL871X)/phydm_rtl8703b.o\ ++ hal/phydm/halrf/$(RTL871X)/halrf_8703b.o ++endif ++ ++ifeq ($(CONFIG_RTL8723D), y) ++RTL871X = rtl8723d ++_PHYDM_FILES += hal/phydm/$(RTL871X)/halhwimg8723d_bb.o\ ++ hal/phydm/$(RTL871X)/halhwimg8723d_mac.o\ ++ hal/phydm/$(RTL871X)/halhwimg8723d_rf.o\ ++ hal/phydm/$(RTL871X)/phydm_regconfig8723d.o\ ++ hal/phydm/$(RTL871X)/phydm_rtl8723d.o\ ++ hal/phydm/halrf/$(RTL871X)/halrf_8723d.o ++endif ++ ++ ++ifeq ($(CONFIG_RTL8710B), y) ++RTL871X = rtl8710b ++_PHYDM_FILES += hal/phydm/$(RTL871X)/halhwimg8710b_bb.o\ ++ hal/phydm/$(RTL871X)/halhwimg8710b_mac.o\ ++ hal/phydm/$(RTL871X)/halhwimg8710b_rf.o\ ++ hal/phydm/$(RTL871X)/phydm_regconfig8710b.o\ ++ hal/phydm/$(RTL871X)/phydm_rtl8710b.o\ ++ hal/phydm/halrf/$(RTL871X)/halrf_8710b.o ++endif ++ ++ ++ifeq ($(CONFIG_RTL8188F), y) ++RTL871X = rtl8188f ++_PHYDM_FILES += hal/phydm/$(RTL871X)/halhwimg8188f_bb.o\ ++ hal/phydm/$(RTL871X)/halhwimg8188f_mac.o\ ++ hal/phydm/$(RTL871X)/halhwimg8188f_rf.o\ ++ hal/phydm/$(RTL871X)/phydm_regconfig8188f.o\ ++ hal/phydm/halrf/$(RTL871X)/halrf_8188f.o \ ++ hal/phydm/$(RTL871X)/phydm_rtl8188f.o ++endif ++ ++ifeq ($(CONFIG_RTL8822B), y) ++RTL871X = rtl8822b ++_PHYDM_FILES += hal/phydm/$(RTL871X)/halhwimg8822b_bb.o \ ++ hal/phydm/$(RTL871X)/halhwimg8822b_mac.o \ ++ hal/phydm/$(RTL871X)/halhwimg8822b_rf.o \ ++ hal/phydm/halrf/$(RTL871X)/halrf_8822b.o \ ++ hal/phydm/$(RTL871X)/phydm_hal_api8822b.o \ ++ hal/phydm/halrf/$(RTL871X)/halrf_iqk_8822b.o \ ++ hal/phydm/halrf/$(RTL871X)/halrf_rfk_init_8822b.o \ ++ hal/phydm/$(RTL871X)/phydm_regconfig8822b.o \ ++ hal/phydm/$(RTL871X)/phydm_rtl8822b.o ++ ++_PHYDM_FILES += hal/phydm/txbf/haltxbf8822b.o ++endif ++ ++ ++ifeq ($(CONFIG_RTL8821C), y) ++RTL871X = rtl8821c ++_PHYDM_FILES += hal/phydm/$(RTL871X)/halhwimg8821c_bb.o \ ++ hal/phydm/$(RTL871X)/halhwimg8821c_mac.o \ ++ hal/phydm/$(RTL871X)/halhwimg8821c_rf.o \ ++ hal/phydm/$(RTL871X)/phydm_hal_api8821c.o \ ++ hal/phydm/$(RTL871X)/phydm_regconfig8821c.o\ ++ hal/phydm/halrf/$(RTL871X)/halrf_8821c.o\ ++ hal/phydm/halrf/$(RTL871X)/halrf_iqk_8821c.o ++endif ++ifeq ($(CONFIG_RTL8192F), y) ++RTL871X = rtl8192f ++_PHYDM_FILES += hal/phydm/$(RTL871X)/halhwimg8192f_bb.o\ ++ hal/phydm/$(RTL871X)/halhwimg8192f_mac.o\ ++ hal/phydm/$(RTL871X)/halhwimg8192f_rf.o\ ++ hal/phydm/$(RTL871X)/phydm_hal_api8192f.o\ ++ hal/phydm/$(RTL871X)/phydm_regconfig8192f.o\ ++ hal/phydm/$(RTL871X)/phydm_rtl8192f.o\ ++ hal/phydm/halrf/$(RTL871X)/halrf_8192f.o ++endif ++ ++ifeq ($(CONFIG_RTL8198F), y) ++RTL871X = rtl8198f ++_PHYDM_FILES += hal/phydm/$(RTL871X)/halhwimg8198f_bb.o\ ++ hal/phydm/$(RTL871X)/halhwimg8198f_mac.o\ ++ hal/phydm/$(RTL871X)/halhwimg8198f_rf.o\ ++ hal/phydm/$(RTL871X)/phydm_hal_api8198f.o\ ++ hal/phydm/$(RTL871X)/phydm_regconfig8198f.o ++endif ++ ++ifeq ($(CONFIG_RTL8822C), y) ++RTL871X = rtl8822c ++_PHYDM_FILES += hal/phydm/$(RTL871X)/halhwimg8822c_bb.o\ ++ hal/phydm/$(RTL871X)/halhwimg8822c_mac.o\ ++ hal/phydm/$(RTL871X)/halhwimg8822c_rf.o\ ++ hal/phydm/$(RTL871X)/phydm_hal_api8822c.o\ ++ hal/phydm/$(RTL871X)/phydm_regconfig8822c.o\ ++ hal/phydm/halrf/$(RTL871X)/halrf_8822c.o\ ++ hal/phydm/halrf/$(RTL871X)/halrf_iqk_8822c.o\ ++ hal/phydm/halrf/$(RTL871X)/halrf_tssi_8822c.o\ ++ hal/phydm/halrf/$(RTL871X)/halrf_dpk_8822c.o\ ++ hal/phydm/halrf/$(RTL871X)/halrf_rfk_init_8822c.o ++endif ++ ++ifeq ($(CONFIG_RTL8814B), y) ++RTL871X = rtl8814b ++_PHYDM_FILES += hal/phydm/$(RTL871X)/halhwimg8814b_bb.o\ ++ hal/phydm/$(RTL871X)/phydm_hal_api8814b.o\ ++ hal/phydm/$(RTL871X)/phydm_regconfig8814b.o\ ++ hal/phydm/halrf/$(RTL871X)/halrf_8814b.o \ ++ hal/phydm/halrf/$(RTL871X)/halrf_iqk_8814b.o \ ++ hal/phydm/halrf/$(RTL871X)/halrf_rfk_init_8814b.o ++endif +\ Ingen nyrad vid filslut +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_mp.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_mp.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_mp.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_mp.c 2021-03-07 18:16:17.063956478 +0200 @@ -0,0 +1,348 @@ +/****************************************************************************** + * @@ -243490,11 +240343,9 @@ index 000000000..7d964f5d6 + mp->io_value = (u32)mp->rx_phy_ok_cnt; +} +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_mp.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_mp.h -new file mode 100644 -index 000000000..40088c6ce ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_mp.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_mp.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_mp.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_mp.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_mp.h 2021-03-07 18:16:17.063956478 +0200 @@ -0,0 +1,94 @@ +/****************************************************************************** + * @@ -243590,11 +240441,9 @@ index 000000000..40088c6ce + +void phydm_mp_get_rx_ok(void *dm_void); +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_noisemonitor.c linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_noisemonitor.c -new file mode 100644 -index 000000000..77fe94e3f ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_noisemonitor.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_noisemonitor.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_noisemonitor.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_noisemonitor.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_noisemonitor.c 2021-03-07 18:16:17.063956478 +0200 @@ -0,0 +1,457 @@ +/****************************************************************************** + * @@ -244053,11 +240902,9 @@ index 000000000..77fe94e3f + total_cca_cnt, total_fa_cnt, dm->noisy_decision_smooth, score, + score_smooth, dm->noisy_decision); +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_noisemonitor.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_noisemonitor.h -new file mode 100644 -index 000000000..507285adb ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_noisemonitor.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_noisemonitor.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_noisemonitor.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_noisemonitor.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_noisemonitor.h 2021-03-07 18:16:17.063956478 +0200 @@ -0,0 +1,48 @@ +/****************************************************************************** + * @@ -244107,11 +240954,9 @@ index 000000000..507285adb +void phydm_noisy_detection(void *dm_void); + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_pathdiv.c linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_pathdiv.c -new file mode 100644 -index 000000000..b3c46d295 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_pathdiv.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_pathdiv.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_pathdiv.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_pathdiv.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_pathdiv.c 2021-03-07 18:16:17.063956478 +0200 @@ -0,0 +1,928 @@ +/****************************************************************************** + * @@ -245041,11 +241886,9 @@ index 000000000..b3c46d295 +} + +#endif /* @#ifdef CONFIG_PATH_DIVERSITY */ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_pathdiv.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_pathdiv.h -new file mode 100644 -index 000000000..132e9cddb ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_pathdiv.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_pathdiv.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_pathdiv.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_pathdiv.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_pathdiv.h 2021-03-07 18:16:17.063956478 +0200 @@ -0,0 +1,123 @@ +/****************************************************************************** + * @@ -245170,12 +242013,10 @@ index 000000000..132e9cddb +#endif /* @#ifdef CONFIG_PATH_DIVERSITY */ +#endif /* @#ifndef __PHYDMPATHDIV_H__ */ + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_phystatus.c linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_phystatus.c -new file mode 100644 -index 000000000..bbcb6bd7b ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_phystatus.c -@@ -0,0 +1,3183 @@ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_phystatus.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_phystatus.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_phystatus.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_phystatus.c 2021-03-07 18:16:17.064956526 +0200 +@@ -0,0 +1,3192 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -246249,7 +243090,6 @@ index 000000000..bbcb6bd7b +#endif + +#if ODM_IC_11AC_SERIES_SUPPORT -+ +void phydm_rx_physts_bw_parsing(struct phydm_phyinfo_struct *phy_info, + struct phydm_perpkt_info_struct * + pktinfo, @@ -246367,6 +243207,16 @@ index 000000000..bbcb6bd7b + + phy_info->rx_pwdb_all = rssi; + phy_info->rx_mimo_signal_strength[0] = rssi; ++ ++ // fill per path rx power info ++ for (i = RF_PATH_A; i < dm->num_rf_path; i++) { ++ if (i < RF_PATH_C) ++ val = phy_sts->gain_trsw[i]; ++ else ++ val = phy_sts->gain_trsw_cd[i - 2]; ++ ++ phy_info->rx_pwr[i] = (val & 0x7F) - 110; ++ } + } else { + /* @== [OFDM rate] ===================================================*/ + for (i = RF_PATH_A; i < dm->num_rf_path; i++) { @@ -248359,11 +245209,9 @@ index 000000000..bbcb6bd7b + + phydm_avg_phystatus_init(dm); +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_phystatus.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_phystatus.h -new file mode 100644 -index 000000000..333fa89bf ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_phystatus.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_phystatus.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_phystatus.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_phystatus.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_phystatus.h 2021-03-07 18:16:17.064956526 +0200 @@ -0,0 +1,1137 @@ +/****************************************************************************** + * @@ -249502,11 +246350,9 @@ index 000000000..333fa89bf +void phydm_rx_phy_status_init(void *dm_void); + +#endif /*@#ifndef __HALHWOUTSRC_H__*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_pmac_tx_setting.c linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_pmac_tx_setting.c -new file mode 100644 -index 000000000..882283c7b ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_pmac_tx_setting.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_pmac_tx_setting.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_pmac_tx_setting.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_pmac_tx_setting.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_pmac_tx_setting.c 2021-03-07 18:16:17.064956526 +0200 @@ -0,0 +1,543 @@ +/****************************************************************************** + * @@ -250051,11 +246897,9 @@ index 000000000..882283c7b +} + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_pmac_tx_setting.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_pmac_tx_setting.h -new file mode 100644 -index 000000000..982733c09 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_pmac_tx_setting.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_pmac_tx_setting.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_pmac_tx_setting.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_pmac_tx_setting.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_pmac_tx_setting.h 2021-03-07 18:16:17.064956526 +0200 @@ -0,0 +1,152 @@ +/****************************************************************************** + * @@ -250209,11 +247053,9 @@ index 000000000..982733c09 +void phydm_set_tmac_tx(void *dm_void); + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_pow_train.c linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_pow_train.c -new file mode 100644 -index 000000000..56bc2411d ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_pow_train.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_pow_train.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_pow_train.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_pow_train.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_pow_train.c 2021-03-07 18:16:17.064956526 +0200 @@ -0,0 +1,171 @@ +/****************************************************************************** + * @@ -250386,11 +247228,9 @@ index 000000000..56bc2411d +} + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_pow_train.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_pow_train.h -new file mode 100644 -index 000000000..f966607aa ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_pow_train.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_pow_train.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_pow_train.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_pow_train.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_pow_train.h 2021-03-07 18:16:17.064956526 +0200 @@ -0,0 +1,84 @@ +/****************************************************************************** + * @@ -250476,11 +247316,527 @@ index 000000000..f966607aa + +#endif +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_pre_define.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_pre_define.h -new file mode 100644 -index 000000000..d8d7313b1 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_pre_define.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_precomp.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_precomp.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_precomp.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_precomp.h 2021-03-07 18:16:17.064956526 +0200 +@@ -0,0 +1,514 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, ++ * Hsinchu 300, Taiwan. ++ * ++ * Larry Finger ++ * ++ *****************************************************************************/ ++ ++#ifndef __ODM_PRECOMP_H__ ++#define __ODM_PRECOMP_H__ ++ ++#include "phydm_types.h" ++#include "halrf/halrf_features.h" ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) ++ #include "Precomp.h" /* @We need to include mp_precomp.h due to batch file setting. */ ++#else ++ #define TEST_FALG___ 1 ++#endif ++ ++/* @2 Config Flags and Structs - defined by each ODM type */ ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_AP) ++ #include "../8192cd_cfg.h" ++ #include "../odm_inc.h" ++ ++ #include "../8192cd.h" ++ #include "../8192cd_util.h" ++ #include "../8192cd_hw.h" ++ #ifdef _BIG_ENDIAN_ ++ #define ODM_ENDIAN_TYPE ODM_ENDIAN_BIG ++ #else ++ #define ODM_ENDIAN_TYPE ODM_ENDIAN_LITTLE ++ #endif ++ ++ #include "../8192cd_headers.h" ++ #include "../8192cd_debug.h" ++ ++#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ #ifdef DM_ODM_CE_MAC80211 ++ #include "../wifi.h" ++ #include "rtl_phydm.h" ++ #elif defined(DM_ODM_CE_MAC80211_V2) ++ #include "../main.h" ++ #include "../hw.h" ++ #include "../fw.h" ++ #endif ++ #define __PACK ++ #define __WLAN_ATTRIB_PACK__ ++#elif (DM_ODM_SUPPORT_TYPE == ODM_WIN) ++ #include "mp_precomp.h" ++ #define ODM_ENDIAN_TYPE ODM_ENDIAN_LITTLE ++ #define __PACK ++ #define __WLAN_ATTRIB_PACK__ ++#elif (DM_ODM_SUPPORT_TYPE == ODM_IOT) ++ #include ++ #include ++ #define ODM_ENDIAN_TYPE ODM_ENDIAN_LITTLE ++ #define __PACK ++#endif ++ ++/* @2 OutSrc Header Files */ ++ ++#include "phydm.h" ++#include "phydm_hwconfig.h" ++#include "phydm_phystatus.h" ++#include "phydm_debug.h" ++#include "phydm_regdefine11ac.h" ++#include "phydm_regdefine11n.h" ++#include "phydm_interface.h" ++#include "phydm_reg.h" ++#include "halrf/halrf_debug.h" ++ ++#if (DM_ODM_SUPPORT_TYPE & ODM_CE) && \ ++ (!defined(DM_ODM_CE_MAC80211) && !defined(DM_ODM_CE_MAC80211_V2)) ++ ++void phy_set_tx_power_limit( ++ struct dm_struct *dm, ++ u8 *regulation, ++ u8 *band, ++ u8 *bandwidth, ++ u8 *rate_section, ++ u8 *rf_path, ++ u8 *channel, ++ u8 *power_limit); ++ ++enum hal_status ++rtw_phydm_fw_iqk( ++ struct dm_struct *dm, ++ u8 clear, ++ u8 segment); ++ ++enum hal_status ++rtw_phydm_cfg_phy_para( ++ struct dm_struct *dm, ++ enum phydm_halmac_param config_type, ++ u32 offset, ++ u32 data, ++ u32 mask, ++ enum rf_path e_rf_path, ++ u32 delay_time); ++ ++#endif ++ ++/* @Judy ADD 20180125 */ ++#if (DM_ODM_SUPPORT_TYPE & (ODM_AP | ODM_IOT)) ++#define RTL8710B_SUPPORT 0 ++#endif ++ ++#if RTL8188E_SUPPORT == 1 ++ #define RTL8188E_T_SUPPORT 1 ++ #ifdef CONFIG_SFW_SUPPORTED ++ #define RTL8188E_S_SUPPORT 1 ++ #else ++ #define RTL8188E_S_SUPPORT 0 ++ #endif ++#endif ++ ++#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE)) ++#define RTL8197F_SUPPORT 0 /*@Just for PHYDM API development*/ ++#define RTL8195B_SUPPORT 0 /*@Just for PHYDM API development*/ ++#define RTL8198F_SUPPORT 0 /*@Just for PHYDM API development*/ ++#define RTL8812F_SUPPORT 0 /*@Just for PHYDM API development*/ ++#define RTL8197G_SUPPORT 0 /*@Just for PHYDM API development*/ ++#endif ++ ++#if (RTL8188E_SUPPORT == 1) ++ #include "rtl8188e/hal8188erateadaptive.h" /* @for RA,Power training */ ++ #include "rtl8188e/halhwimg8188e_mac.h" ++ #include "rtl8188e/halhwimg8188e_rf.h" ++ #include "rtl8188e/halhwimg8188e_bb.h" ++ #include "rtl8188e/phydm_regconfig8188e.h" ++ #include "rtl8188e/phydm_rtl8188e.h" ++ #include "rtl8188e/hal8188ereg.h" ++ #include "rtl8188e/version_rtl8188e.h" ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ #include "rtl8188e_hal.h" ++ #include "halrf/rtl8188e/halrf_8188e_ce.h" ++ #endif ++ #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) ++ #include "halrf/rtl8188e/halrf_8188e_win.h" ++ #endif ++ #if (DM_ODM_SUPPORT_TYPE == ODM_AP) ++ #include "halrf/rtl8188e/halrf_8188e_ap.h" ++ #endif ++#endif /* @88E END */ ++ ++#if (RTL8192E_SUPPORT == 1) ++ ++ #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) ++ #include "halrf/rtl8192e/halrf_8192e_win.h" /*@FOR_8192E_IQK*/ ++ #elif (DM_ODM_SUPPORT_TYPE == ODM_AP) ++ #include "halrf/rtl8192e/halrf_8192e_ap.h" /*@FOR_8192E_IQK*/ ++ #elif (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ #include "halrf/rtl8192e/halrf_8192e_ce.h" /*@FOR_8192E_IQK*/ ++ #endif ++ ++ #include "rtl8192e/phydm_rtl8192e.h" /* @FOR_8192E_IQK */ ++ #include "rtl8192e/version_rtl8192e.h" ++ #if (DM_ODM_SUPPORT_TYPE != ODM_AP) ++ #include "rtl8192e/halhwimg8192e_bb.h" ++ #include "rtl8192e/halhwimg8192e_mac.h" ++ #include "rtl8192e/halhwimg8192e_rf.h" ++ #include "rtl8192e/phydm_regconfig8192e.h" ++ #include "rtl8192e/hal8192ereg.h" ++ #endif ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ #include "rtl8192e_hal.h" ++ #endif ++#endif /* @92E END */ ++ ++#if (RTL8812A_SUPPORT == 1) ++ ++ #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) ++ #include "halrf/rtl8812a/halrf_8812a_win.h" ++ #elif (DM_ODM_SUPPORT_TYPE == ODM_AP) ++ #include "halrf/rtl8812a/halrf_8812a_ap.h" ++ #elif (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ #include "halrf/rtl8812a/halrf_8812a_ce.h" ++ #endif ++ ++ /* @#include "halrf/rtl8812a/halrf_8812a.h" */ /* @FOR_8812_IQK */ ++ #if (DM_ODM_SUPPORT_TYPE != ODM_AP) ++ #include "rtl8812a/halhwimg8812a_bb.h" ++ #include "rtl8812a/halhwimg8812a_mac.h" ++ #include "rtl8812a/halhwimg8812a_rf.h" ++ #include "rtl8812a/phydm_regconfig8812a.h" ++ #endif ++ #include "rtl8812a/phydm_rtl8812a.h" ++ ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ #include "rtl8812a_hal.h" ++ #endif ++ #include "rtl8812a/version_rtl8812a.h" ++ ++#endif /* @8812 END */ ++ ++#if (RTL8814A_SUPPORT == 1) ++ ++ #include "rtl8814a/halhwimg8814a_mac.h" ++ #include "rtl8814a/halhwimg8814a_rf.h" ++ #include "rtl8814a/halhwimg8814a_bb.h" ++ #include "rtl8814a/version_rtl8814a.h" ++ #include "rtl8814a/phydm_rtl8814a.h" ++ #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) ++ #include "halrf/rtl8814a/halrf_8814a_win.h" ++ #elif (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ #include "halrf/rtl8814a/halrf_8814a_ce.h" ++ #elif (DM_ODM_SUPPORT_TYPE == ODM_AP) ++ #include "halrf/rtl8814a/halrf_8814a_ap.h" ++ #endif ++ #include "rtl8814a/phydm_regconfig8814a.h" ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ #include "rtl8814a_hal.h" ++ #include "halrf/rtl8814a/halrf_iqk_8814a.h" ++ #endif ++#endif /* @8814 END */ ++ ++#if (RTL8881A_SUPPORT == 1)/* @FOR_8881_IQK */ ++ #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) ++ #include "halrf/rtl8821a/halrf_iqk_8821a_win.h" ++ #elif (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ #include "halrf/rtl8821a/halrf_iqk_8821a_ce.h" ++ #else ++ #include "halrf/rtl8821a/halrf_iqk_8821a_ap.h" ++ #endif ++ /* @#include "rtl8881a/HalHWImg8881A_BB.h" */ ++ /* @#include "rtl8881a/HalHWImg8881A_MAC.h" */ ++ /* @#include "rtl8881a/HalHWImg8881A_RF.h" */ ++ /* @#include "rtl8881a/odm_RegConfig8881A.h" */ ++#endif ++ ++#if (RTL8723B_SUPPORT == 1) ++ #include "rtl8723b/halhwimg8723b_mac.h" ++ #include "rtl8723b/halhwimg8723b_rf.h" ++ #include "rtl8723b/halhwimg8723b_bb.h" ++ #include "rtl8723b/phydm_regconfig8723b.h" ++ #include "rtl8723b/phydm_rtl8723b.h" ++ #include "rtl8723b/hal8723breg.h" ++ #include "rtl8723b/version_rtl8723b.h" ++ #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) ++ #include "halrf/rtl8723b/halrf_8723b_win.h" ++ #elif (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ #include "halrf/rtl8723b/halrf_8723b_ce.h" ++ #include "rtl8723b/halhwimg8723b_mp.h" ++ #include "rtl8723b_hal.h" ++ #else ++ #include "halrf/rtl8723b/halrf_8723b_ap.h" ++ #endif ++#endif ++ ++#if (RTL8821A_SUPPORT == 1) ++ #include "rtl8821a/halhwimg8821a_mac.h" ++ #include "rtl8821a/halhwimg8821a_rf.h" ++ #include "rtl8821a/halhwimg8821a_bb.h" ++ #include "rtl8821a/phydm_regconfig8821a.h" ++ #include "rtl8821a/phydm_rtl8821a.h" ++ #include "rtl8821a/version_rtl8821a.h" ++ #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) ++ #include "halrf/rtl8821a/halrf_8821a_win.h" ++ #elif (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ #include "halrf/rtl8821a/halrf_8821a_ce.h" ++ #include "halrf/rtl8821a/halrf_iqk_8821a_ce.h"/*@for IQK*/ ++ #include "halrf/rtl8812a/halrf_8812a_ce.h"/*@for IQK,LCK,Power-tracking*/ ++ #include "rtl8812a_hal.h" ++ #else ++ #endif ++#endif ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_CE) && defined(DM_ODM_CE_MAC80211) ++#include "../halmac/halmac_reg2.h" ++#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) && defined(DM_ODM_CE_MAC80211_V2) ++#include "../halmac/halmac_reg2.h" ++#endif ++ ++ ++#if (RTL8822B_SUPPORT == 1) ++ #include "rtl8822b/halhwimg8822b_mac.h" ++ #include "rtl8822b/halhwimg8822b_rf.h" ++ #include "rtl8822b/halhwimg8822b_bb.h" ++ #include "rtl8822b/phydm_regconfig8822b.h" ++ #include "halrf/rtl8822b/halrf_8822b.h" ++ #include "rtl8822b/phydm_rtl8822b.h" ++ #include "rtl8822b/phydm_hal_api8822b.h" ++ #include "rtl8822b/version_rtl8822b.h" ++ ++ #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) ++ #elif (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ #ifdef DM_ODM_CE_MAC80211 ++ #include "../halmac/halmac_reg_8822b.h" ++ #elif defined(DM_ODM_CE_MAC80211_V2) ++ #include "../halmac/halmac_reg_8822b.h" ++ #else ++ #include /* @struct HAL_DATA_TYPE */ ++ #include /* @RX_SMOOTH_FACTOR, reg definition and etc.*/ ++ #endif ++ #elif (DM_ODM_SUPPORT_TYPE == ODM_AP) ++ #endif ++ ++#endif ++ ++#if (RTL8703B_SUPPORT == 1) ++ #include "rtl8703b/phydm_rtl8703b.h" ++ #include "rtl8703b/phydm_regconfig8703b.h" ++ #include "rtl8703b/halhwimg8703b_mac.h" ++ #include "rtl8703b/halhwimg8703b_rf.h" ++ #include "rtl8703b/halhwimg8703b_bb.h" ++ #include "halrf/rtl8703b/halrf_8703b.h" ++ #include "rtl8703b/version_rtl8703b.h" ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ #include "rtl8703b_hal.h" ++ #endif ++#endif ++ ++#if (RTL8188F_SUPPORT == 1) ++ #include "rtl8188f/halhwimg8188f_mac.h" ++ #include "rtl8188f/halhwimg8188f_rf.h" ++ #include "rtl8188f/halhwimg8188f_bb.h" ++ #include "rtl8188f/hal8188freg.h" ++ #include "rtl8188f/phydm_rtl8188f.h" ++ #include "rtl8188f/phydm_regconfig8188f.h" ++ #include "halrf/rtl8188f/halrf_8188f.h" /*@for IQK,LCK,Power-tracking*/ ++ #include "rtl8188f/version_rtl8188f.h" ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ #include "rtl8188f_hal.h" ++ #endif ++#endif ++ ++#if (RTL8723D_SUPPORT == 1) ++ #if (DM_ODM_SUPPORT_TYPE != ODM_AP) ++ ++ #include "rtl8723d/halhwimg8723d_bb.h" ++ #include "rtl8723d/halhwimg8723d_mac.h" ++ #include "rtl8723d/halhwimg8723d_rf.h" ++ #include "rtl8723d/phydm_regconfig8723d.h" ++ #include "rtl8723d/hal8723dreg.h" ++ #include "rtl8723d/phydm_rtl8723d.h" ++ #include "halrf/rtl8723d/halrf_8723d.h" ++ #include "rtl8723d/version_rtl8723d.h" ++ #endif ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ #ifdef DM_ODM_CE_MAC80211 ++ #else ++ #include "rtl8723d_hal.h" ++ #endif ++ #endif ++#endif /* @8723D End */ ++ ++#if (RTL8710B_SUPPORT == 1) ++ #if (DM_ODM_SUPPORT_TYPE != ODM_AP) ++ ++ #include "rtl8710b/halhwimg8710b_bb.h" ++ #include "rtl8710b/halhwimg8710b_mac.h" ++ #include "rtl8710b/halhwimg8710b_rf.h" ++ #include "rtl8710b/phydm_regconfig8710b.h" ++ #include "rtl8710b/hal8710breg.h" ++ #include "rtl8710b/phydm_rtl8710b.h" ++ #include "halrf/rtl8710b/halrf_8710b.h" ++ #include "rtl8710b/version_rtl8710b.h" ++ #endif ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ #include "rtl8710b_hal.h" ++ #endif ++#endif /* @8710B End */ ++ ++#if (RTL8197F_SUPPORT == 1) ++ #include "rtl8197f/halhwimg8197f_mac.h" ++ #include "rtl8197f/halhwimg8197f_rf.h" ++ #include "rtl8197f/halhwimg8197f_bb.h" ++ #include "rtl8197f/phydm_hal_api8197f.h" ++ #include "rtl8197f/version_rtl8197f.h" ++ #include "rtl8197f/phydm_rtl8197f.h" ++ #include "rtl8197f/phydm_regconfig8197f.h" ++ #include "halrf/rtl8197f/halrf_8197f.h" ++ #include "halrf/rtl8197f/halrf_iqk_8197f.h" ++ #include "halrf/rtl8197f/halrf_dpk_8197f.h" ++#endif ++ ++#if (RTL8821C_SUPPORT == 1) ++ #include "rtl8821c/phydm_hal_api8821c.h" ++ #include "rtl8821c/halhwimg8821c_mac.h" ++ #include "rtl8821c/halhwimg8821c_rf.h" ++ #include "rtl8821c/halhwimg8821c_bb.h" ++ #include "rtl8821c/phydm_regconfig8821c.h" ++ #include "halrf/rtl8821c/halrf_8821c.h" ++ #include "rtl8821c/version_rtl8821c.h" ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ #ifdef DM_ODM_CE_MAC80211 ++ #include "../halmac/halmac_reg_8821c.h" ++ #else ++ #include "rtl8821c_hal.h" ++ #endif ++ #endif ++#endif ++ ++#if (RTL8192F_SUPPORT == 1) ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ #include "rtl8192f_hal.h"/*need to before rf.h*/ ++ #endif ++ #include "rtl8192f/halhwimg8192f_mac.h" ++ #include "rtl8192f/halhwimg8192f_rf.h" ++ #include "rtl8192f/halhwimg8192f_bb.h" ++ #include "rtl8192f/phydm_hal_api8192f.h" ++ #include "rtl8192f/version_rtl8192f.h" ++ #include "rtl8192f/phydm_rtl8192f.h" ++ #include "rtl8192f/phydm_regconfig8192f.h" ++ #include "halrf/rtl8192f/halrf_8192f.h" ++ #if (DM_ODM_SUPPORT_TYPE == ODM_AP) ++ #include "halrf/rtl8192f/halrf_dpk_8192f.h" ++ #endif ++#endif ++ ++#if (RTL8721D_SUPPORT == 1) ++ #include "halrf/rtl8721d/halrf_8721d.h" ++ #include "rtl8721d/phydm_hal_api8721d.h" ++ #include "rtl8721d/phydm_regconfig8721d.h" ++ #include "rtl8721d/halhwimg8721d_mac.h" ++ #include "rtl8721d/halhwimg8721d_rf.h" ++ #include "rtl8721d/halhwimg8721d_bb.h" ++ #include "rtl8721d/version_rtl8721d.h" ++ #include "rtl8721d/phydm_rtl8721d.h" ++ #include "rtl8721d/hal8721dreg.h" ++ #include ++ #if 0 ++ #if (DM_ODM_SUPPORT_TYPE == ODM_AP) ++ #include "halrf/rtl8721d/halrf_dpk_8721d.h" ++ #endif ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ #include "rtl8721d_hal.h" ++ #endif ++ #endif ++#endif ++#if (RTL8195B_SUPPORT == 1) ++ #include "halrf/rtl8195b/halrf_8195b.h" ++ #include "rtl8195b/phydm_hal_api8195b.h" ++ #include "rtl8195b/phydm_regconfig8195b.h" ++ #include "rtl8195b/halhwimg8195b_mac.h" ++ #include "rtl8195b/halhwimg8195b_rf.h" ++ #include "rtl8195b/halhwimg8195b_bb.h" ++ #include "rtl8195b/version_rtl8195b.h" ++ #include /*@HAL_DATA_TYPE*/ ++#endif ++ ++#if (RTL8198F_SUPPORT == 1) ++ #include "rtl8198f/phydm_regconfig8198f.h" ++ #include "rtl8198f/phydm_hal_api8198f.h" ++ #include "rtl8198f/halhwimg8198f_mac.h" ++ #include "rtl8198f/halhwimg8198f_rf.h" ++ #include "rtl8198f/halhwimg8198f_bb.h" ++ #include "rtl8198f/version_rtl8198f.h" ++ #include "halrf/rtl8198f/halrf_8198f.h" ++ #include "halrf/rtl8198f/halrf_iqk_8198f.h" ++#endif ++ ++#if (RTL8822C_SUPPORT) ++ #include "rtl8822c/halhwimg8822c_mac.h" ++ #include "rtl8822c/halhwimg8822c_rf.h" ++ #include "rtl8822c/halhwimg8822c_bb.h" ++ #include "rtl8822c/phydm_regconfig8822c.h" ++ #include "halrf/rtl8822c/halrf_8822c.h" ++ #include "rtl8822c/phydm_hal_api8822c.h" ++ #include "rtl8822c/version_rtl8822c.h" ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ /* @struct HAL_DATA_TYPE */ ++ #include ++ /* @RX_SMOOTH_FACTOR, reg definition and etc.*/ ++ #include ++ #endif ++#endif ++#if (RTL8814B_SUPPORT == 1) ++ #include "rtl8814b/halhwimg8814b_mac.h" ++ #include "rtl8814b/halhwimg8814b_rf.h" ++ #include "rtl8814b/halhwimg8814b_bb.h" ++ #include "rtl8814b/phydm_regconfig8814b.h" ++ #include "halrf/rtl8814b/halrf_8814b.h" ++ #include "rtl8814b/phydm_hal_api8814b.h" ++ #include "rtl8814b/version_rtl8814b.h" ++#endif ++#if (RTL8812F_SUPPORT) ++ #include "rtl8812f/halhwimg8812f_mac.h" ++ #include "rtl8812f/halhwimg8812f_rf.h" ++ #include "rtl8812f/halhwimg8812f_bb.h" ++ #include "rtl8812f/phydm_regconfig8812f.h" ++ #include "halrf/rtl8812f/halrf_8812f.h" ++ #include "rtl8812f/phydm_hal_api8812f.h" ++ #include "rtl8812f/version_rtl8812f.h" ++#endif ++#if (RTL8197G_SUPPORT) ++ #include "rtl8197g/halhwimg8197g_mac.h" ++ #include "rtl8197g/halhwimg8197g_rf.h" ++ #include "rtl8197g/halhwimg8197g_bb.h" ++ #include "rtl8197g/phydm_regconfig8197g.h" ++ #include "halrf/rtl8197g/halrf_8197g.h" ++ #include "rtl8197g/phydm_hal_api8197g.h" ++ #include "rtl8197g/version_rtl8197g.h" ++#endif ++#endif /* @__ODM_PRECOMP_H__ */ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_pre_define.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_pre_define.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_pre_define.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_pre_define.h 2021-03-07 18:16:17.064956526 +0200 @@ -0,0 +1,849 @@ +/****************************************************************************** + * @@ -251331,531 +248687,9 @@ index 000000000..d8d7313b1 +}; + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_precomp.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_precomp.h -new file mode 100644 -index 000000000..78b8945fc ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_precomp.h -@@ -0,0 +1,514 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * The full GNU General Public License is included in this distribution in the -+ * file called LICENSE. -+ * -+ * Contact Information: -+ * wlanfae -+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, -+ * Hsinchu 300, Taiwan. -+ * -+ * Larry Finger -+ * -+ *****************************************************************************/ -+ -+#ifndef __ODM_PRECOMP_H__ -+#define __ODM_PRECOMP_H__ -+ -+#include "phydm_types.h" -+#include "halrf/halrf_features.h" -+ -+#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) -+ #include "Precomp.h" /* @We need to include mp_precomp.h due to batch file setting. */ -+#else -+ #define TEST_FALG___ 1 -+#endif -+ -+/* @2 Config Flags and Structs - defined by each ODM type */ -+ -+#if (DM_ODM_SUPPORT_TYPE == ODM_AP) -+ #include "../8192cd_cfg.h" -+ #include "../odm_inc.h" -+ -+ #include "../8192cd.h" -+ #include "../8192cd_util.h" -+ #include "../8192cd_hw.h" -+ #ifdef _BIG_ENDIAN_ -+ #define ODM_ENDIAN_TYPE ODM_ENDIAN_BIG -+ #else -+ #define ODM_ENDIAN_TYPE ODM_ENDIAN_LITTLE -+ #endif -+ -+ #include "../8192cd_headers.h" -+ #include "../8192cd_debug.h" -+ -+#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) -+ #ifdef DM_ODM_CE_MAC80211 -+ #include "../wifi.h" -+ #include "rtl_phydm.h" -+ #elif defined(DM_ODM_CE_MAC80211_V2) -+ #include "../main.h" -+ #include "../hw.h" -+ #include "../fw.h" -+ #endif -+ #define __PACK -+ #define __WLAN_ATTRIB_PACK__ -+#elif (DM_ODM_SUPPORT_TYPE == ODM_WIN) -+ #include "mp_precomp.h" -+ #define ODM_ENDIAN_TYPE ODM_ENDIAN_LITTLE -+ #define __PACK -+ #define __WLAN_ATTRIB_PACK__ -+#elif (DM_ODM_SUPPORT_TYPE == ODM_IOT) -+ #include -+ #include -+ #define ODM_ENDIAN_TYPE ODM_ENDIAN_LITTLE -+ #define __PACK -+#endif -+ -+/* @2 OutSrc Header Files */ -+ -+#include "phydm.h" -+#include "phydm_hwconfig.h" -+#include "phydm_phystatus.h" -+#include "phydm_debug.h" -+#include "phydm_regdefine11ac.h" -+#include "phydm_regdefine11n.h" -+#include "phydm_interface.h" -+#include "phydm_reg.h" -+#include "halrf/halrf_debug.h" -+ -+#if (DM_ODM_SUPPORT_TYPE & ODM_CE) && \ -+ (!defined(DM_ODM_CE_MAC80211) && !defined(DM_ODM_CE_MAC80211_V2)) -+ -+void phy_set_tx_power_limit( -+ struct dm_struct *dm, -+ u8 *regulation, -+ u8 *band, -+ u8 *bandwidth, -+ u8 *rate_section, -+ u8 *rf_path, -+ u8 *channel, -+ u8 *power_limit); -+ -+enum hal_status -+rtw_phydm_fw_iqk( -+ struct dm_struct *dm, -+ u8 clear, -+ u8 segment); -+ -+enum hal_status -+rtw_phydm_cfg_phy_para( -+ struct dm_struct *dm, -+ enum phydm_halmac_param config_type, -+ u32 offset, -+ u32 data, -+ u32 mask, -+ enum rf_path e_rf_path, -+ u32 delay_time); -+ -+#endif -+ -+/* @Judy ADD 20180125 */ -+#if (DM_ODM_SUPPORT_TYPE & (ODM_AP | ODM_IOT)) -+#define RTL8710B_SUPPORT 0 -+#endif -+ -+#if RTL8188E_SUPPORT == 1 -+ #define RTL8188E_T_SUPPORT 1 -+ #ifdef CONFIG_SFW_SUPPORTED -+ #define RTL8188E_S_SUPPORT 1 -+ #else -+ #define RTL8188E_S_SUPPORT 0 -+ #endif -+#endif -+ -+#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE)) -+#define RTL8197F_SUPPORT 0 /*@Just for PHYDM API development*/ -+#define RTL8195B_SUPPORT 0 /*@Just for PHYDM API development*/ -+#define RTL8198F_SUPPORT 0 /*@Just for PHYDM API development*/ -+#define RTL8812F_SUPPORT 0 /*@Just for PHYDM API development*/ -+#define RTL8197G_SUPPORT 0 /*@Just for PHYDM API development*/ -+#endif -+ -+#if (RTL8188E_SUPPORT == 1) -+ #include "rtl8188e/hal8188erateadaptive.h" /* @for RA,Power training */ -+ #include "rtl8188e/halhwimg8188e_mac.h" -+ #include "rtl8188e/halhwimg8188e_rf.h" -+ #include "rtl8188e/halhwimg8188e_bb.h" -+ #include "rtl8188e/phydm_regconfig8188e.h" -+ #include "rtl8188e/phydm_rtl8188e.h" -+ #include "rtl8188e/hal8188ereg.h" -+ #include "rtl8188e/version_rtl8188e.h" -+ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) -+ #include "rtl8188e_hal.h" -+ #include "halrf/rtl8188e/halrf_8188e_ce.h" -+ #endif -+ #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) -+ #include "halrf/rtl8188e/halrf_8188e_win.h" -+ #endif -+ #if (DM_ODM_SUPPORT_TYPE == ODM_AP) -+ #include "halrf/rtl8188e/halrf_8188e_ap.h" -+ #endif -+#endif /* @88E END */ -+ -+#if (RTL8192E_SUPPORT == 1) -+ -+ #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) -+ #include "halrf/rtl8192e/halrf_8192e_win.h" /*@FOR_8192E_IQK*/ -+ #elif (DM_ODM_SUPPORT_TYPE == ODM_AP) -+ #include "halrf/rtl8192e/halrf_8192e_ap.h" /*@FOR_8192E_IQK*/ -+ #elif (DM_ODM_SUPPORT_TYPE == ODM_CE) -+ #include "halrf/rtl8192e/halrf_8192e_ce.h" /*@FOR_8192E_IQK*/ -+ #endif -+ -+ #include "rtl8192e/phydm_rtl8192e.h" /* @FOR_8192E_IQK */ -+ #include "rtl8192e/version_rtl8192e.h" -+ #if (DM_ODM_SUPPORT_TYPE != ODM_AP) -+ #include "rtl8192e/halhwimg8192e_bb.h" -+ #include "rtl8192e/halhwimg8192e_mac.h" -+ #include "rtl8192e/halhwimg8192e_rf.h" -+ #include "rtl8192e/phydm_regconfig8192e.h" -+ #include "rtl8192e/hal8192ereg.h" -+ #endif -+ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) -+ #include "rtl8192e_hal.h" -+ #endif -+#endif /* @92E END */ -+ -+#if (RTL8812A_SUPPORT == 1) -+ -+ #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) -+ #include "halrf/rtl8812a/halrf_8812a_win.h" -+ #elif (DM_ODM_SUPPORT_TYPE == ODM_AP) -+ #include "halrf/rtl8812a/halrf_8812a_ap.h" -+ #elif (DM_ODM_SUPPORT_TYPE == ODM_CE) -+ #include "halrf/rtl8812a/halrf_8812a_ce.h" -+ #endif -+ -+ /* @#include "halrf/rtl8812a/halrf_8812a.h" */ /* @FOR_8812_IQK */ -+ #if (DM_ODM_SUPPORT_TYPE != ODM_AP) -+ #include "rtl8812a/halhwimg8812a_bb.h" -+ #include "rtl8812a/halhwimg8812a_mac.h" -+ #include "rtl8812a/halhwimg8812a_rf.h" -+ #include "rtl8812a/phydm_regconfig8812a.h" -+ #endif -+ #include "rtl8812a/phydm_rtl8812a.h" -+ -+ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) -+ #include "rtl8812a_hal.h" -+ #endif -+ #include "rtl8812a/version_rtl8812a.h" -+ -+#endif /* @8812 END */ -+ -+#if (RTL8814A_SUPPORT == 1) -+ -+ #include "rtl8814a/halhwimg8814a_mac.h" -+ #include "rtl8814a/halhwimg8814a_rf.h" -+ #include "rtl8814a/halhwimg8814a_bb.h" -+ #include "rtl8814a/version_rtl8814a.h" -+ #include "rtl8814a/phydm_rtl8814a.h" -+ #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) -+ #include "halrf/rtl8814a/halrf_8814a_win.h" -+ #elif (DM_ODM_SUPPORT_TYPE == ODM_CE) -+ #include "halrf/rtl8814a/halrf_8814a_ce.h" -+ #elif (DM_ODM_SUPPORT_TYPE == ODM_AP) -+ #include "halrf/rtl8814a/halrf_8814a_ap.h" -+ #endif -+ #include "rtl8814a/phydm_regconfig8814a.h" -+ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) -+ #include "rtl8814a_hal.h" -+ #include "halrf/rtl8814a/halrf_iqk_8814a.h" -+ #endif -+#endif /* @8814 END */ -+ -+#if (RTL8881A_SUPPORT == 1)/* @FOR_8881_IQK */ -+ #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) -+ #include "halrf/rtl8821a/halrf_iqk_8821a_win.h" -+ #elif (DM_ODM_SUPPORT_TYPE == ODM_CE) -+ #include "halrf/rtl8821a/halrf_iqk_8821a_ce.h" -+ #else -+ #include "halrf/rtl8821a/halrf_iqk_8821a_ap.h" -+ #endif -+ /* @#include "rtl8881a/HalHWImg8881A_BB.h" */ -+ /* @#include "rtl8881a/HalHWImg8881A_MAC.h" */ -+ /* @#include "rtl8881a/HalHWImg8881A_RF.h" */ -+ /* @#include "rtl8881a/odm_RegConfig8881A.h" */ -+#endif -+ -+#if (RTL8723B_SUPPORT == 1) -+ #include "rtl8723b/halhwimg8723b_mac.h" -+ #include "rtl8723b/halhwimg8723b_rf.h" -+ #include "rtl8723b/halhwimg8723b_bb.h" -+ #include "rtl8723b/phydm_regconfig8723b.h" -+ #include "rtl8723b/phydm_rtl8723b.h" -+ #include "rtl8723b/hal8723breg.h" -+ #include "rtl8723b/version_rtl8723b.h" -+ #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) -+ #include "halrf/rtl8723b/halrf_8723b_win.h" -+ #elif (DM_ODM_SUPPORT_TYPE == ODM_CE) -+ #include "halrf/rtl8723b/halrf_8723b_ce.h" -+ #include "rtl8723b/halhwimg8723b_mp.h" -+ #include "rtl8723b_hal.h" -+ #else -+ #include "halrf/rtl8723b/halrf_8723b_ap.h" -+ #endif -+#endif -+ -+#if (RTL8821A_SUPPORT == 1) -+ #include "rtl8821a/halhwimg8821a_mac.h" -+ #include "rtl8821a/halhwimg8821a_rf.h" -+ #include "rtl8821a/halhwimg8821a_bb.h" -+ #include "rtl8821a/phydm_regconfig8821a.h" -+ #include "rtl8821a/phydm_rtl8821a.h" -+ #include "rtl8821a/version_rtl8821a.h" -+ #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) -+ #include "halrf/rtl8821a/halrf_8821a_win.h" -+ #elif (DM_ODM_SUPPORT_TYPE == ODM_CE) -+ #include "halrf/rtl8821a/halrf_8821a_ce.h" -+ #include "halrf/rtl8821a/halrf_iqk_8821a_ce.h"/*@for IQK*/ -+ #include "halrf/rtl8812a/halrf_8812a_ce.h"/*@for IQK,LCK,Power-tracking*/ -+ #include "rtl8812a_hal.h" -+ #else -+ #endif -+#endif -+ -+#if (DM_ODM_SUPPORT_TYPE == ODM_CE) && defined(DM_ODM_CE_MAC80211) -+#include "../halmac/halmac_reg2.h" -+#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) && defined(DM_ODM_CE_MAC80211_V2) -+#include "../halmac/halmac_reg2.h" -+#endif -+ -+ -+#if (RTL8822B_SUPPORT == 1) -+ #include "rtl8822b/halhwimg8822b_mac.h" -+ #include "rtl8822b/halhwimg8822b_rf.h" -+ #include "rtl8822b/halhwimg8822b_bb.h" -+ #include "rtl8822b/phydm_regconfig8822b.h" -+ #include "halrf/rtl8822b/halrf_8822b.h" -+ #include "rtl8822b/phydm_rtl8822b.h" -+ #include "rtl8822b/phydm_hal_api8822b.h" -+ #include "rtl8822b/version_rtl8822b.h" -+ -+ #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) -+ #elif (DM_ODM_SUPPORT_TYPE == ODM_CE) -+ #ifdef DM_ODM_CE_MAC80211 -+ #include "../halmac/halmac_reg_8822b.h" -+ #elif defined(DM_ODM_CE_MAC80211_V2) -+ #include "../halmac/halmac_reg_8822b.h" -+ #else -+ #include /* @struct HAL_DATA_TYPE */ -+ #include /* @RX_SMOOTH_FACTOR, reg definition and etc.*/ -+ #endif -+ #elif (DM_ODM_SUPPORT_TYPE == ODM_AP) -+ #endif -+ -+#endif -+ -+#if (RTL8703B_SUPPORT == 1) -+ #include "rtl8703b/phydm_rtl8703b.h" -+ #include "rtl8703b/phydm_regconfig8703b.h" -+ #include "rtl8703b/halhwimg8703b_mac.h" -+ #include "rtl8703b/halhwimg8703b_rf.h" -+ #include "rtl8703b/halhwimg8703b_bb.h" -+ #include "halrf/rtl8703b/halrf_8703b.h" -+ #include "rtl8703b/version_rtl8703b.h" -+ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) -+ #include "rtl8703b_hal.h" -+ #endif -+#endif -+ -+#if (RTL8188F_SUPPORT == 1) -+ #include "rtl8188f/halhwimg8188f_mac.h" -+ #include "rtl8188f/halhwimg8188f_rf.h" -+ #include "rtl8188f/halhwimg8188f_bb.h" -+ #include "rtl8188f/hal8188freg.h" -+ #include "rtl8188f/phydm_rtl8188f.h" -+ #include "rtl8188f/phydm_regconfig8188f.h" -+ #include "halrf/rtl8188f/halrf_8188f.h" /*@for IQK,LCK,Power-tracking*/ -+ #include "rtl8188f/version_rtl8188f.h" -+ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) -+ #include "rtl8188f_hal.h" -+ #endif -+#endif -+ -+#if (RTL8723D_SUPPORT == 1) -+ #if (DM_ODM_SUPPORT_TYPE != ODM_AP) -+ -+ #include "rtl8723d/halhwimg8723d_bb.h" -+ #include "rtl8723d/halhwimg8723d_mac.h" -+ #include "rtl8723d/halhwimg8723d_rf.h" -+ #include "rtl8723d/phydm_regconfig8723d.h" -+ #include "rtl8723d/hal8723dreg.h" -+ #include "rtl8723d/phydm_rtl8723d.h" -+ #include "halrf/rtl8723d/halrf_8723d.h" -+ #include "rtl8723d/version_rtl8723d.h" -+ #endif -+ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) -+ #ifdef DM_ODM_CE_MAC80211 -+ #else -+ #include "rtl8723d_hal.h" -+ #endif -+ #endif -+#endif /* @8723D End */ -+ -+#if (RTL8710B_SUPPORT == 1) -+ #if (DM_ODM_SUPPORT_TYPE != ODM_AP) -+ -+ #include "rtl8710b/halhwimg8710b_bb.h" -+ #include "rtl8710b/halhwimg8710b_mac.h" -+ #include "rtl8710b/halhwimg8710b_rf.h" -+ #include "rtl8710b/phydm_regconfig8710b.h" -+ #include "rtl8710b/hal8710breg.h" -+ #include "rtl8710b/phydm_rtl8710b.h" -+ #include "halrf/rtl8710b/halrf_8710b.h" -+ #include "rtl8710b/version_rtl8710b.h" -+ #endif -+ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) -+ #include "rtl8710b_hal.h" -+ #endif -+#endif /* @8710B End */ -+ -+#if (RTL8197F_SUPPORT == 1) -+ #include "rtl8197f/halhwimg8197f_mac.h" -+ #include "rtl8197f/halhwimg8197f_rf.h" -+ #include "rtl8197f/halhwimg8197f_bb.h" -+ #include "rtl8197f/phydm_hal_api8197f.h" -+ #include "rtl8197f/version_rtl8197f.h" -+ #include "rtl8197f/phydm_rtl8197f.h" -+ #include "rtl8197f/phydm_regconfig8197f.h" -+ #include "halrf/rtl8197f/halrf_8197f.h" -+ #include "halrf/rtl8197f/halrf_iqk_8197f.h" -+ #include "halrf/rtl8197f/halrf_dpk_8197f.h" -+#endif -+ -+#if (RTL8821C_SUPPORT == 1) -+ #include "rtl8821c/phydm_hal_api8821c.h" -+ #include "rtl8821c/halhwimg8821c_mac.h" -+ #include "rtl8821c/halhwimg8821c_rf.h" -+ #include "rtl8821c/halhwimg8821c_bb.h" -+ #include "rtl8821c/phydm_regconfig8821c.h" -+ #include "halrf/rtl8821c/halrf_8821c.h" -+ #include "rtl8821c/version_rtl8821c.h" -+ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) -+ #ifdef DM_ODM_CE_MAC80211 -+ #include "../halmac/halmac_reg_8821c.h" -+ #else -+ #include "rtl8821c_hal.h" -+ #endif -+ #endif -+#endif -+ -+#if (RTL8192F_SUPPORT == 1) -+ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) -+ #include "rtl8192f_hal.h"/*need to before rf.h*/ -+ #endif -+ #include "rtl8192f/halhwimg8192f_mac.h" -+ #include "rtl8192f/halhwimg8192f_rf.h" -+ #include "rtl8192f/halhwimg8192f_bb.h" -+ #include "rtl8192f/phydm_hal_api8192f.h" -+ #include "rtl8192f/version_rtl8192f.h" -+ #include "rtl8192f/phydm_rtl8192f.h" -+ #include "rtl8192f/phydm_regconfig8192f.h" -+ #include "halrf/rtl8192f/halrf_8192f.h" -+ #if (DM_ODM_SUPPORT_TYPE == ODM_AP) -+ #include "halrf/rtl8192f/halrf_dpk_8192f.h" -+ #endif -+#endif -+ -+#if (RTL8721D_SUPPORT == 1) -+ #include "halrf/rtl8721d/halrf_8721d.h" -+ #include "rtl8721d/phydm_hal_api8721d.h" -+ #include "rtl8721d/phydm_regconfig8721d.h" -+ #include "rtl8721d/halhwimg8721d_mac.h" -+ #include "rtl8721d/halhwimg8721d_rf.h" -+ #include "rtl8721d/halhwimg8721d_bb.h" -+ #include "rtl8721d/version_rtl8721d.h" -+ #include "rtl8721d/phydm_rtl8721d.h" -+ #include "rtl8721d/hal8721dreg.h" -+ #include -+ #if 0 -+ #if (DM_ODM_SUPPORT_TYPE == ODM_AP) -+ #include "halrf/rtl8721d/halrf_dpk_8721d.h" -+ #endif -+ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) -+ #include "rtl8721d_hal.h" -+ #endif -+ #endif -+#endif -+#if (RTL8195B_SUPPORT == 1) -+ #include "halrf/rtl8195b/halrf_8195b.h" -+ #include "rtl8195b/phydm_hal_api8195b.h" -+ #include "rtl8195b/phydm_regconfig8195b.h" -+ #include "rtl8195b/halhwimg8195b_mac.h" -+ #include "rtl8195b/halhwimg8195b_rf.h" -+ #include "rtl8195b/halhwimg8195b_bb.h" -+ #include "rtl8195b/version_rtl8195b.h" -+ #include /*@HAL_DATA_TYPE*/ -+#endif -+ -+#if (RTL8198F_SUPPORT == 1) -+ #include "rtl8198f/phydm_regconfig8198f.h" -+ #include "rtl8198f/phydm_hal_api8198f.h" -+ #include "rtl8198f/halhwimg8198f_mac.h" -+ #include "rtl8198f/halhwimg8198f_rf.h" -+ #include "rtl8198f/halhwimg8198f_bb.h" -+ #include "rtl8198f/version_rtl8198f.h" -+ #include "halrf/rtl8198f/halrf_8198f.h" -+ #include "halrf/rtl8198f/halrf_iqk_8198f.h" -+#endif -+ -+#if (RTL8822C_SUPPORT) -+ #include "rtl8822c/halhwimg8822c_mac.h" -+ #include "rtl8822c/halhwimg8822c_rf.h" -+ #include "rtl8822c/halhwimg8822c_bb.h" -+ #include "rtl8822c/phydm_regconfig8822c.h" -+ #include "halrf/rtl8822c/halrf_8822c.h" -+ #include "rtl8822c/phydm_hal_api8822c.h" -+ #include "rtl8822c/version_rtl8822c.h" -+ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) -+ /* @struct HAL_DATA_TYPE */ -+ #include -+ /* @RX_SMOOTH_FACTOR, reg definition and etc.*/ -+ #include -+ #endif -+#endif -+#if (RTL8814B_SUPPORT == 1) -+ #include "rtl8814b/halhwimg8814b_mac.h" -+ #include "rtl8814b/halhwimg8814b_rf.h" -+ #include "rtl8814b/halhwimg8814b_bb.h" -+ #include "rtl8814b/phydm_regconfig8814b.h" -+ #include "halrf/rtl8814b/halrf_8814b.h" -+ #include "rtl8814b/phydm_hal_api8814b.h" -+ #include "rtl8814b/version_rtl8814b.h" -+#endif -+#if (RTL8812F_SUPPORT) -+ #include "rtl8812f/halhwimg8812f_mac.h" -+ #include "rtl8812f/halhwimg8812f_rf.h" -+ #include "rtl8812f/halhwimg8812f_bb.h" -+ #include "rtl8812f/phydm_regconfig8812f.h" -+ #include "halrf/rtl8812f/halrf_8812f.h" -+ #include "rtl8812f/phydm_hal_api8812f.h" -+ #include "rtl8812f/version_rtl8812f.h" -+#endif -+#if (RTL8197G_SUPPORT) -+ #include "rtl8197g/halhwimg8197g_mac.h" -+ #include "rtl8197g/halhwimg8197g_rf.h" -+ #include "rtl8197g/halhwimg8197g_bb.h" -+ #include "rtl8197g/phydm_regconfig8197g.h" -+ #include "halrf/rtl8197g/halrf_8197g.h" -+ #include "rtl8197g/phydm_hal_api8197g.h" -+ #include "rtl8197g/version_rtl8197g.h" -+#endif -+#endif /* @__ODM_PRECOMP_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_primary_cca.c linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_primary_cca.c -new file mode 100644 -index 000000000..dec6c5365 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_primary_cca.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_primary_cca.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_primary_cca.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_primary_cca.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_primary_cca.c 2021-03-07 18:16:17.064956526 +0200 @@ -0,0 +1,173 @@ +/****************************************************************************** + * @@ -252030,11 +248864,9 @@ index 000000000..dec6c5365 +#endif +} +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_primary_cca.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_primary_cca.h -new file mode 100644 -index 000000000..9a647502d ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_primary_cca.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_primary_cca.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_primary_cca.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_primary_cca.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_primary_cca.h 2021-03-07 18:16:17.064956526 +0200 @@ -0,0 +1,87 @@ +/****************************************************************************** + * @@ -252123,11 +248955,9 @@ index 000000000..9a647502d +#endif /*@#ifdef PHYDM_PRIMARY_CCA*/ +#endif /*@#ifndef __PHYDM_PRIMARYCCA_H__*/ + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_psd.c linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_psd.c -new file mode 100644 -index 000000000..458677b59 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_psd.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_psd.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_psd.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_psd.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_psd.c 2021-03-07 18:16:17.064956526 +0200 @@ -0,0 +1,459 @@ +/****************************************************************************** + * @@ -252588,11 +249418,9 @@ index 000000000..458677b59 +} + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_psd.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_psd.h -new file mode 100644 -index 000000000..635a887cb ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_psd.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_psd.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_psd.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_psd.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_psd.h 2021-03-07 18:16:17.064956526 +0200 @@ -0,0 +1,66 @@ +/****************************************************************************** + * @@ -252660,11 +249488,9 @@ index 000000000..635a887cb + +#endif +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_rainfo.c linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_rainfo.c -new file mode 100644 -index 000000000..077585dfc ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_rainfo.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_rainfo.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_rainfo.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_rainfo.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_rainfo.c 2021-03-07 18:16:17.064956526 +0200 @@ -0,0 +1,2085 @@ +/****************************************************************************** + * @@ -254751,11 +251577,9 @@ index 000000000..077585dfc +} + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_rainfo.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_rainfo.h -new file mode 100644 -index 000000000..a840880a4 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_rainfo.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_rainfo.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_rainfo.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_rainfo.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_rainfo.h 2021-03-07 18:16:17.065956573 +0200 @@ -0,0 +1,276 @@ +/****************************************************************************** + * @@ -255033,11 +251857,345 @@ index 000000000..a840880a4 + void *dm_void); +#endif +#endif /*@#ifndef __PHYDMRAINFO_H__*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_reg.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_reg.h -new file mode 100644 -index 000000000..310322479 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_reg.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_regdefine11ac.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_regdefine11ac.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_regdefine11ac.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_regdefine11ac.h 2021-03-07 18:16:17.065956573 +0200 +@@ -0,0 +1,109 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, ++ * Hsinchu 300, Taiwan. ++ * ++ * Larry Finger ++ * ++ *****************************************************************************/ ++ ++#ifndef __ODM_REGDEFINE11AC_H__ ++#define __ODM_REGDEFINE11AC_H__ ++ ++/* @2 RF REG LIST */ ++ ++ ++ ++/* @2 BB REG LIST */ ++/* PAGE 8 */ ++#define ODM_REG_CCK_RPT_FORMAT_11AC 0x804 ++#define ODM_REG_BB_RX_PATH_11AC 0x808 ++#define ODM_REG_BB_TX_PATH_11AC 0x80c ++#define ODM_REG_BB_ATC_11AC 0x860 ++#define ODM_REG_EDCCA_POWER_CAL 0x8dc ++#define ODM_REG_DBG_RPT_11AC 0x8fc ++/* PAGE 9 */ ++#define ODM_REG_EDCCA_DOWN_OPT 0x900 ++#define ODM_REG_ACBB_EDCCA_ENHANCE 0x944 ++#define odm_adc_trigger_jaguar2 0x95C /*@ADC sample mode*/ ++#define ODM_REG_OFDM_FA_RST_11AC 0x9A4 ++#define ODM_REG_CCX_PERIOD_11AC 0x990 ++#define ODM_REG_NHM_TH9_TH10_11AC 0x994 ++#define ODM_REG_CLM_11AC 0x994 ++#define ODM_REG_NHM_TH3_TO_TH0_11AC 0x998 ++#define ODM_REG_NHM_TH7_TO_TH4_11AC 0x99c ++#define ODM_REG_NHM_TH8_11AC 0x9a0 ++#define ODM_REG_NHM_9E8_11AC 0x9e8 ++#define ODM_REG_CSI_CONTENT_VALUE 0x9b4 ++/* PAGE A */ ++#define ODM_REG_CCK_CCA_11AC 0xA0A ++#define ODM_REG_CCK_FA_RST_11AC 0xA2C ++#define ODM_REG_CCK_FA_11AC 0xA5C ++/* PAGE B */ ++#define ODM_REG_RST_RPT_11AC 0xB58 ++/* PAGE C */ ++#define ODM_REG_TRMUX_11AC 0xC08 ++#define ODM_REG_IGI_A_11AC 0xC50 ++/* PAGE E */ ++#define ODM_REG_IGI_B_11AC 0xE50 ++#define ODM_REG_ANT_11AC_B 0xE08 ++/* PAGE F */ ++#define ODM_REG_CCK_CRC32_CNT_11AC 0xF04 ++#define ODM_REG_CCK_CCA_CNT_11AC 0xF08 ++#define ODM_REG_VHT_CRC32_CNT_11AC 0xF0c ++#define ODM_REG_HT_CRC32_CNT_11AC 0xF10 ++#define ODM_REG_OFDM_CRC32_CNT_11AC 0xF14 ++#define ODM_REG_OFDM_FA_11AC 0xF48 ++#define ODM_REG_OFDM_FA_TYPE1_11AC 0xFCC ++#define ODM_REG_OFDM_FA_TYPE2_11AC 0xFD0 ++#define ODM_REG_OFDM_FA_TYPE3_11AC 0xFBC ++#define ODM_REG_OFDM_FA_TYPE4_11AC 0xFC0 ++#define ODM_REG_OFDM_FA_TYPE5_11AC 0xFC4 ++#define ODM_REG_OFDM_FA_TYPE6_11AC 0xFC8 ++#define ODM_REG_RPT_11AC 0xfa0 ++#define ODM_REG_CLM_RESULT_11AC 0xfa4 ++#define ODM_REG_NHM_CNT_11AC 0xfa8 ++#define ODM_REG_NHM_DUR_READY_11AC 0xfb4 ++ ++#define ODM_REG_NHM_CNT7_TO_CNT4_11AC 0xfac ++#define ODM_REG_NHM_CNT11_TO_CNT8_11AC 0xfb0 ++/* PAGE 18 */ ++#define ODM_REG_IGI_C_11AC 0x1850 ++/* PAGE 1A */ ++#define ODM_REG_IGI_D_11AC 0x1A50 ++ ++/* PAGE 1D */ ++#define ODM_REG_IGI_11AC3 0x1D70 ++ ++/* @2 MAC REG LIST */ ++#define ODM_REG_RESP_TX_11AC 0x6D8 ++ ++ ++ ++/* @DIG Related */ ++#define ODM_BIT_IGI_11AC 0x0000007F ++#define ODM_BIT_IGI_B_11AC3 0x00007F00 ++#define ODM_BIT_IGI_C_11AC3 0x007F0000 ++#define ODM_BIT_IGI_D_11AC3 0x7F000000 ++#define ODM_BIT_CCK_RPT_FORMAT_11AC BIT(16) ++#define ODM_BIT_BB_RX_PATH_11AC 0xF ++#define ODM_BIT_BB_TX_PATH_11AC 0xF ++#define ODM_BIT_BB_ATC_11AC BIT(14) ++ ++#endif +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_regdefine11n.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_regdefine11n.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_regdefine11n.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_regdefine11n.h 2021-03-07 18:16:17.065956573 +0200 +@@ -0,0 +1,219 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, ++ * Hsinchu 300, Taiwan. ++ * ++ * Larry Finger ++ * ++ *****************************************************************************/ ++ ++#ifndef __ODM_REGDEFINE11N_H__ ++#define __ODM_REGDEFINE11N_H__ ++ ++/* @2 RF REG LIST */ ++#define ODM_REG_RF_MODE_11N 0x00 ++#define ODM_REG_RF_0B_11N 0x0B ++#define ODM_REG_CHNBW_11N 0x18 ++#define ODM_REG_T_METER_11N 0x24 ++#define ODM_REG_RF_25_11N 0x25 ++#define ODM_REG_RF_26_11N 0x26 ++#define ODM_REG_RF_27_11N 0x27 ++#define ODM_REG_RF_2B_11N 0x2B ++#define ODM_REG_RF_2C_11N 0x2C ++#define ODM_REG_RXRF_A3_11N 0x3C ++#define ODM_REG_T_METER_92D_11N 0x42 ++#define ODM_REG_T_METER_88E_11N 0x42 ++ ++ ++ ++/* @2 BB REG LIST ++ * PAGE 8 ++ */ ++#define ODM_REG_BB_CTRL_11N 0x800 ++#define ODM_REG_RF_PIN_11N 0x804 ++#define ODM_REG_PSD_CTRL_11N 0x808 ++#define ODM_REG_TX_ANT_CTRL_11N 0x80C ++#define ODM_REG_BB_PWR_SAV5_11N 0x818 ++#define ODM_REG_CCK_RPT_FORMAT_11N 0x824 ++#define ODM_REG_CCK_RPT_FORMAT_11N_B 0x82C ++#define ODM_REG_RX_DEFAULT_A_11N 0x858 ++#define ODM_REG_RX_DEFAULT_B_11N 0x85A ++#define ODM_REG_BB_PWR_SAV3_11N 0x85C ++#define ODM_REG_ANTSEL_CTRL_11N 0x860 ++#define ODM_REG_RX_ANT_CTRL_11N 0x864 ++#define ODM_REG_PIN_CTRL_11N 0x870 ++#define ODM_REG_BB_PWR_SAV1_11N 0x874 ++#define ODM_REG_ANTSEL_PATH_11N 0x878 ++#define ODM_REG_BB_3WIRE_11N 0x88C ++#define ODM_REG_SC_CNT_11N 0x8C4 ++#define ODM_REG_PSD_DATA_11N 0x8B4 ++#define ODM_REG_CCX_PERIOD_11N 0x894 ++#define ODM_REG_NHM_TH9_TH10_11N 0x890 ++#define ODM_REG_CLM_11N 0x890 ++#define ODM_REG_NHM_TH3_TO_TH0_11N 0x898 ++#define ODM_REG_NHM_TH7_TO_TH4_11N 0x89c ++#define ODM_REG_NHM_TH8_11N 0xe28 ++#define ODM_REG_CLM_READY_11N 0x8b4 ++#define ODM_REG_CLM_RESULT_11N 0x8d0 ++#define ODM_REG_NHM_CNT_11N 0x8d8 ++ ++/* @For struct acs_info, Jeffery, 2014-12-26 */ ++#define ODM_REG_NHM_CNT7_TO_CNT4_11N 0x8dc ++#define ODM_REG_NHM_CNT9_TO_CNT8_11N 0x8d0 ++#define ODM_REG_NHM_CNT10_TO_CNT11_11N 0x8d4 ++ ++/* PAGE 9 */ ++#define ODM_REG_BB_CTRL_PAGE9_11N 0x900 ++#define ODM_REG_DBG_RPT_11N 0x908 ++#define ODM_REG_BB_TX_PATH_11N 0x90c ++#define ODM_REG_ANT_MAPPING1_11N 0x914 ++#define ODM_REG_ANT_MAPPING2_11N 0x918 ++#define ODM_REG_EDCCA_DOWN_OPT_11N 0x948 ++#define ODM_REG_RX_DFIR_MOD_97F 0x948 ++#define ODM_REG_SOML_97F 0x998 ++ ++/* PAGE A */ ++#define ODM_REG_CCK_ANTDIV_PARA1_11N 0xA00 ++#define ODM_REG_CCK_ANT_SEL_11N 0xA04 ++#define ODM_REG_CCK_CCA_11N 0xA0A ++#define ODM_REG_CCK_ANTDIV_PARA2_11N 0xA0C ++#define ODM_REG_CCK_ANTDIV_PARA3_11N 0xA10 ++#define ODM_REG_CCK_ANTDIV_PARA4_11N 0xA14 ++#define ODM_REG_CCK_FILTER_PARA1_11N 0xA22 ++#define ODM_REG_CCK_FILTER_PARA2_11N 0xA23 ++#define ODM_REG_CCK_FILTER_PARA3_11N 0xA24 ++#define ODM_REG_CCK_FILTER_PARA4_11N 0xA25 ++#define ODM_REG_CCK_FILTER_PARA5_11N 0xA26 ++#define ODM_REG_CCK_FILTER_PARA6_11N 0xA27 ++#define ODM_REG_CCK_FILTER_PARA7_11N 0xA28 ++#define ODM_REG_CCK_FILTER_PARA8_11N 0xA29 ++#define ODM_REG_CCK_FA_RST_11N 0xA2C ++#define ODM_REG_CCK_FA_MSB_11N 0xA58 ++#define ODM_REG_CCK_FA_LSB_11N 0xA5C ++#define ODM_REG_CCK_CCA_CNT_11N 0xA60 ++#define ODM_REG_BB_PWR_SAV4_11N 0xA74 ++/* PAGE B */ ++#define ODM_REG_LNA_SWITCH_11N 0xB2C ++#define ODM_REG_PATH_SWITCH_11N 0xB30 ++#define ODM_REG_RSSI_CTRL_11N 0xB38 ++#define ODM_REG_CONFIG_ANTA_11N 0xB68 ++#define ODM_REG_RSSI_BT_11N 0xB9C ++#define ODM_REG_RXCK_RFMOD 0xBB0 ++#define ODM_REG_EDCCA_DCNF_97F 0xBC0 ++ ++/* PAGE C */ ++#define ODM_REG_OFDM_FA_HOLDC_11N 0xC00 ++#define ODM_REG_BB_RX_PATH_11N 0xC04 ++#define ODM_REG_TRMUX_11N 0xC08 ++#define ODM_REG_OFDM_FA_RSTC_11N 0xC0C ++#define ODM_REG_DOWNSAM_FACTOR_11N 0xC10 ++#define ODM_REG_RXIQI_MATRIX_11N 0xC14 ++#define ODM_REG_TXIQK_MATRIX_LSB1_11N 0xC4C ++#define ODM_REG_IGI_A_11N 0xC50 ++#define ODM_REG_ANTDIV_PARA2_11N 0xC54 ++#define ODM_REG_IGI_B_11N 0xC58 ++#define ODM_REG_ANTDIV_PARA3_11N 0xC5C ++#define ODM_REG_L1SBD_PD_CH_11N 0XC6C ++#define ODM_REG_BB_PWR_SAV2_11N 0xC70 ++#define ODM_REG_BB_AGC_SET_2_11N 0xc74 ++#define ODM_REG_RX_OFF_11N 0xC7C ++#define ODM_REG_TXIQK_MATRIXA_11N 0xC80 ++#define ODM_REG_TXIQK_MATRIXB_11N 0xC88 ++#define ODM_REG_TXIQK_MATRIXA_LSB2_11N 0xC94 ++#define ODM_REG_TXIQK_MATRIXB_LSB2_11N 0xC9C ++#define ODM_REG_RXIQK_MATRIX_LSB_11N 0xCA0 ++#define ODM_REG_ANTDIV_PARA1_11N 0xCA4 ++#define ODM_REG_SMALL_BANDWIDTH_11N 0xCE4 ++#define ODM_REG_OFDM_FA_TYPE1_11N 0xCF0 ++/* PAGE D */ ++#define ODM_REG_OFDM_FA_RSTD_11N 0xD00 ++#define ODM_REG_BB_RX_ANT_11N 0xD04 ++#define ODM_REG_BB_ATC_11N 0xD2C ++#define ODM_REG_OFDM_FA_TYPE2_11N 0xDA0 ++#define ODM_REG_OFDM_FA_TYPE3_11N 0xDA4 ++#define ODM_REG_OFDM_FA_TYPE4_11N 0xDA8 ++#define ODM_REG_RPT_11N 0xDF4 ++/* PAGE E */ ++#define ODM_REG_TXAGC_A_6_18_11N 0xE00 ++#define ODM_REG_TXAGC_A_24_54_11N 0xE04 ++#define ODM_REG_TXAGC_A_1_MCS32_11N 0xE08 ++#define ODM_REG_TXAGC_A_MCS0_3_11N 0xE10 ++#define ODM_REG_TXAGC_A_MCS4_7_11N 0xE14 ++#define ODM_REG_TXAGC_A_MCS8_11_11N 0xE18 ++#define ODM_REG_TXAGC_A_MCS12_15_11N 0xE1C ++#define ODM_REG_EDCCA_DCNF_11N 0xE24 ++#define ODM_REG_TAP_UPD_97F 0xE24 ++#define ODM_REG_FPGA0_IQK_11N 0xE28 ++#define ODM_REG_PAGE_B1_97F 0xE28 ++#define ODM_REG_TXIQK_TONE_A_11N 0xE30 ++#define ODM_REG_RXIQK_TONE_A_11N 0xE34 ++#define ODM_REG_TXIQK_PI_A_11N 0xE38 ++#define ODM_REG_RXIQK_PI_A_11N 0xE3C ++#define ODM_REG_TXIQK_11N 0xE40 ++#define ODM_REG_RXIQK_11N 0xE44 ++#define ODM_REG_IQK_AGC_PTS_11N 0xE48 ++#define ODM_REG_IQK_AGC_RSP_11N 0xE4C ++#define ODM_REG_BLUETOOTH_11N 0xE6C ++#define ODM_REG_RX_WAIT_CCA_11N 0xE70 ++#define ODM_REG_TX_CCK_RFON_11N 0xE74 ++#define ODM_REG_TX_CCK_BBON_11N 0xE78 ++#define ODM_REG_OFDM_RFON_11N 0xE7C ++#define ODM_REG_OFDM_BBON_11N 0xE80 ++#define ODM_REG_TX2RX_11N 0xE84 ++#define ODM_REG_TX2TX_11N 0xE88 ++#define ODM_REG_RX_CCK_11N 0xE8C ++#define ODM_REG_RX_OFDM_11N 0xED0 ++#define ODM_REG_RX_WAIT_RIFS_11N 0xED4 ++#define ODM_REG_RX2RX_11N 0xED8 ++#define ODM_REG_STANDBY_11N 0xEDC ++#define ODM_REG_SLEEP_11N 0xEE0 ++#define ODM_REG_PMPD_ANAEN_11N 0xEEC ++/* PAGE F */ ++#define ODM_REG_PAGE_F_RST_11N 0xF14 ++#define ODM_REG_IGI_C_11N 0xF84 ++#define ODM_REG_IGI_D_11N 0xF88 ++#define ODM_REG_CCK_CRC32_ERROR_CNT_11N 0xF84 ++#define ODM_REG_CCK_CRC32_OK_CNT_11N 0xF88 ++#define ODM_REG_HT_CRC32_CNT_11N 0xF90 ++#define ODM_REG_OFDM_CRC32_CNT_11N 0xF94 ++#define ODM_REG_HT_CRC32_CNT_11N_AGG 0xFB8 ++ ++/* @2 MAC REG LIST */ ++#define ODM_REG_BB_RST_11N 0x02 ++#define ODM_REG_ANTSEL_PIN_11N 0x4C ++#define ODM_REG_EARLY_MODE_11N 0x4D0 ++#define ODM_REG_RSSI_MONITOR_11N 0x4FE ++#define ODM_REG_EDCA_VO_11N 0x500 ++#define ODM_REG_EDCA_VI_11N 0x504 ++#define ODM_REG_EDCA_BE_11N 0x508 ++#define ODM_REG_EDCA_BK_11N 0x50C ++#define ODM_REG_TXPAUSE_11N 0x522 ++#define ODM_REG_RESP_TX_11N 0x6D8 ++#define ODM_REG_ANT_TRAIN_PARA1_11N 0x7b0 ++#define ODM_REG_ANT_TRAIN_PARA2_11N 0x7b4 ++ ++ ++/* @DIG Related */ ++#define ODM_BIT_IGI_11N 0x0000007F ++#define ODM_BIT_CCK_RPT_FORMAT_11N BIT(9) ++#define ODM_BIT_BB_RX_PATH_11N 0xF ++#define ODM_BIT_BB_TX_PATH_11N 0xF ++#define ODM_BIT_BB_ATC_11N BIT(11) ++#endif ++ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_reg.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_reg.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_reg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_reg.h 2021-03-07 18:16:17.065956573 +0200 @@ -0,0 +1,241 @@ +/****************************************************************************** + * @@ -255280,351 +252438,9 @@ index 000000000..310322479 +#define BIT_FA_RESET BIT(0) + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_regdefine11ac.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_regdefine11ac.h -new file mode 100644 -index 000000000..7824ac22c ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_regdefine11ac.h -@@ -0,0 +1,109 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * The full GNU General Public License is included in this distribution in the -+ * file called LICENSE. -+ * -+ * Contact Information: -+ * wlanfae -+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, -+ * Hsinchu 300, Taiwan. -+ * -+ * Larry Finger -+ * -+ *****************************************************************************/ -+ -+#ifndef __ODM_REGDEFINE11AC_H__ -+#define __ODM_REGDEFINE11AC_H__ -+ -+/* @2 RF REG LIST */ -+ -+ -+ -+/* @2 BB REG LIST */ -+/* PAGE 8 */ -+#define ODM_REG_CCK_RPT_FORMAT_11AC 0x804 -+#define ODM_REG_BB_RX_PATH_11AC 0x808 -+#define ODM_REG_BB_TX_PATH_11AC 0x80c -+#define ODM_REG_BB_ATC_11AC 0x860 -+#define ODM_REG_EDCCA_POWER_CAL 0x8dc -+#define ODM_REG_DBG_RPT_11AC 0x8fc -+/* PAGE 9 */ -+#define ODM_REG_EDCCA_DOWN_OPT 0x900 -+#define ODM_REG_ACBB_EDCCA_ENHANCE 0x944 -+#define odm_adc_trigger_jaguar2 0x95C /*@ADC sample mode*/ -+#define ODM_REG_OFDM_FA_RST_11AC 0x9A4 -+#define ODM_REG_CCX_PERIOD_11AC 0x990 -+#define ODM_REG_NHM_TH9_TH10_11AC 0x994 -+#define ODM_REG_CLM_11AC 0x994 -+#define ODM_REG_NHM_TH3_TO_TH0_11AC 0x998 -+#define ODM_REG_NHM_TH7_TO_TH4_11AC 0x99c -+#define ODM_REG_NHM_TH8_11AC 0x9a0 -+#define ODM_REG_NHM_9E8_11AC 0x9e8 -+#define ODM_REG_CSI_CONTENT_VALUE 0x9b4 -+/* PAGE A */ -+#define ODM_REG_CCK_CCA_11AC 0xA0A -+#define ODM_REG_CCK_FA_RST_11AC 0xA2C -+#define ODM_REG_CCK_FA_11AC 0xA5C -+/* PAGE B */ -+#define ODM_REG_RST_RPT_11AC 0xB58 -+/* PAGE C */ -+#define ODM_REG_TRMUX_11AC 0xC08 -+#define ODM_REG_IGI_A_11AC 0xC50 -+/* PAGE E */ -+#define ODM_REG_IGI_B_11AC 0xE50 -+#define ODM_REG_ANT_11AC_B 0xE08 -+/* PAGE F */ -+#define ODM_REG_CCK_CRC32_CNT_11AC 0xF04 -+#define ODM_REG_CCK_CCA_CNT_11AC 0xF08 -+#define ODM_REG_VHT_CRC32_CNT_11AC 0xF0c -+#define ODM_REG_HT_CRC32_CNT_11AC 0xF10 -+#define ODM_REG_OFDM_CRC32_CNT_11AC 0xF14 -+#define ODM_REG_OFDM_FA_11AC 0xF48 -+#define ODM_REG_OFDM_FA_TYPE1_11AC 0xFCC -+#define ODM_REG_OFDM_FA_TYPE2_11AC 0xFD0 -+#define ODM_REG_OFDM_FA_TYPE3_11AC 0xFBC -+#define ODM_REG_OFDM_FA_TYPE4_11AC 0xFC0 -+#define ODM_REG_OFDM_FA_TYPE5_11AC 0xFC4 -+#define ODM_REG_OFDM_FA_TYPE6_11AC 0xFC8 -+#define ODM_REG_RPT_11AC 0xfa0 -+#define ODM_REG_CLM_RESULT_11AC 0xfa4 -+#define ODM_REG_NHM_CNT_11AC 0xfa8 -+#define ODM_REG_NHM_DUR_READY_11AC 0xfb4 -+ -+#define ODM_REG_NHM_CNT7_TO_CNT4_11AC 0xfac -+#define ODM_REG_NHM_CNT11_TO_CNT8_11AC 0xfb0 -+/* PAGE 18 */ -+#define ODM_REG_IGI_C_11AC 0x1850 -+/* PAGE 1A */ -+#define ODM_REG_IGI_D_11AC 0x1A50 -+ -+/* PAGE 1D */ -+#define ODM_REG_IGI_11AC3 0x1D70 -+ -+/* @2 MAC REG LIST */ -+#define ODM_REG_RESP_TX_11AC 0x6D8 -+ -+ -+ -+/* @DIG Related */ -+#define ODM_BIT_IGI_11AC 0x0000007F -+#define ODM_BIT_IGI_B_11AC3 0x00007F00 -+#define ODM_BIT_IGI_C_11AC3 0x007F0000 -+#define ODM_BIT_IGI_D_11AC3 0x7F000000 -+#define ODM_BIT_CCK_RPT_FORMAT_11AC BIT(16) -+#define ODM_BIT_BB_RX_PATH_11AC 0xF -+#define ODM_BIT_BB_TX_PATH_11AC 0xF -+#define ODM_BIT_BB_ATC_11AC BIT(14) -+ -+#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_regdefine11n.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_regdefine11n.h -new file mode 100644 -index 000000000..e36f37df6 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_regdefine11n.h -@@ -0,0 +1,219 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * The full GNU General Public License is included in this distribution in the -+ * file called LICENSE. -+ * -+ * Contact Information: -+ * wlanfae -+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, -+ * Hsinchu 300, Taiwan. -+ * -+ * Larry Finger -+ * -+ *****************************************************************************/ -+ -+#ifndef __ODM_REGDEFINE11N_H__ -+#define __ODM_REGDEFINE11N_H__ -+ -+/* @2 RF REG LIST */ -+#define ODM_REG_RF_MODE_11N 0x00 -+#define ODM_REG_RF_0B_11N 0x0B -+#define ODM_REG_CHNBW_11N 0x18 -+#define ODM_REG_T_METER_11N 0x24 -+#define ODM_REG_RF_25_11N 0x25 -+#define ODM_REG_RF_26_11N 0x26 -+#define ODM_REG_RF_27_11N 0x27 -+#define ODM_REG_RF_2B_11N 0x2B -+#define ODM_REG_RF_2C_11N 0x2C -+#define ODM_REG_RXRF_A3_11N 0x3C -+#define ODM_REG_T_METER_92D_11N 0x42 -+#define ODM_REG_T_METER_88E_11N 0x42 -+ -+ -+ -+/* @2 BB REG LIST -+ * PAGE 8 -+ */ -+#define ODM_REG_BB_CTRL_11N 0x800 -+#define ODM_REG_RF_PIN_11N 0x804 -+#define ODM_REG_PSD_CTRL_11N 0x808 -+#define ODM_REG_TX_ANT_CTRL_11N 0x80C -+#define ODM_REG_BB_PWR_SAV5_11N 0x818 -+#define ODM_REG_CCK_RPT_FORMAT_11N 0x824 -+#define ODM_REG_CCK_RPT_FORMAT_11N_B 0x82C -+#define ODM_REG_RX_DEFAULT_A_11N 0x858 -+#define ODM_REG_RX_DEFAULT_B_11N 0x85A -+#define ODM_REG_BB_PWR_SAV3_11N 0x85C -+#define ODM_REG_ANTSEL_CTRL_11N 0x860 -+#define ODM_REG_RX_ANT_CTRL_11N 0x864 -+#define ODM_REG_PIN_CTRL_11N 0x870 -+#define ODM_REG_BB_PWR_SAV1_11N 0x874 -+#define ODM_REG_ANTSEL_PATH_11N 0x878 -+#define ODM_REG_BB_3WIRE_11N 0x88C -+#define ODM_REG_SC_CNT_11N 0x8C4 -+#define ODM_REG_PSD_DATA_11N 0x8B4 -+#define ODM_REG_CCX_PERIOD_11N 0x894 -+#define ODM_REG_NHM_TH9_TH10_11N 0x890 -+#define ODM_REG_CLM_11N 0x890 -+#define ODM_REG_NHM_TH3_TO_TH0_11N 0x898 -+#define ODM_REG_NHM_TH7_TO_TH4_11N 0x89c -+#define ODM_REG_NHM_TH8_11N 0xe28 -+#define ODM_REG_CLM_READY_11N 0x8b4 -+#define ODM_REG_CLM_RESULT_11N 0x8d0 -+#define ODM_REG_NHM_CNT_11N 0x8d8 -+ -+/* @For struct acs_info, Jeffery, 2014-12-26 */ -+#define ODM_REG_NHM_CNT7_TO_CNT4_11N 0x8dc -+#define ODM_REG_NHM_CNT9_TO_CNT8_11N 0x8d0 -+#define ODM_REG_NHM_CNT10_TO_CNT11_11N 0x8d4 -+ -+/* PAGE 9 */ -+#define ODM_REG_BB_CTRL_PAGE9_11N 0x900 -+#define ODM_REG_DBG_RPT_11N 0x908 -+#define ODM_REG_BB_TX_PATH_11N 0x90c -+#define ODM_REG_ANT_MAPPING1_11N 0x914 -+#define ODM_REG_ANT_MAPPING2_11N 0x918 -+#define ODM_REG_EDCCA_DOWN_OPT_11N 0x948 -+#define ODM_REG_RX_DFIR_MOD_97F 0x948 -+#define ODM_REG_SOML_97F 0x998 -+ -+/* PAGE A */ -+#define ODM_REG_CCK_ANTDIV_PARA1_11N 0xA00 -+#define ODM_REG_CCK_ANT_SEL_11N 0xA04 -+#define ODM_REG_CCK_CCA_11N 0xA0A -+#define ODM_REG_CCK_ANTDIV_PARA2_11N 0xA0C -+#define ODM_REG_CCK_ANTDIV_PARA3_11N 0xA10 -+#define ODM_REG_CCK_ANTDIV_PARA4_11N 0xA14 -+#define ODM_REG_CCK_FILTER_PARA1_11N 0xA22 -+#define ODM_REG_CCK_FILTER_PARA2_11N 0xA23 -+#define ODM_REG_CCK_FILTER_PARA3_11N 0xA24 -+#define ODM_REG_CCK_FILTER_PARA4_11N 0xA25 -+#define ODM_REG_CCK_FILTER_PARA5_11N 0xA26 -+#define ODM_REG_CCK_FILTER_PARA6_11N 0xA27 -+#define ODM_REG_CCK_FILTER_PARA7_11N 0xA28 -+#define ODM_REG_CCK_FILTER_PARA8_11N 0xA29 -+#define ODM_REG_CCK_FA_RST_11N 0xA2C -+#define ODM_REG_CCK_FA_MSB_11N 0xA58 -+#define ODM_REG_CCK_FA_LSB_11N 0xA5C -+#define ODM_REG_CCK_CCA_CNT_11N 0xA60 -+#define ODM_REG_BB_PWR_SAV4_11N 0xA74 -+/* PAGE B */ -+#define ODM_REG_LNA_SWITCH_11N 0xB2C -+#define ODM_REG_PATH_SWITCH_11N 0xB30 -+#define ODM_REG_RSSI_CTRL_11N 0xB38 -+#define ODM_REG_CONFIG_ANTA_11N 0xB68 -+#define ODM_REG_RSSI_BT_11N 0xB9C -+#define ODM_REG_RXCK_RFMOD 0xBB0 -+#define ODM_REG_EDCCA_DCNF_97F 0xBC0 -+ -+/* PAGE C */ -+#define ODM_REG_OFDM_FA_HOLDC_11N 0xC00 -+#define ODM_REG_BB_RX_PATH_11N 0xC04 -+#define ODM_REG_TRMUX_11N 0xC08 -+#define ODM_REG_OFDM_FA_RSTC_11N 0xC0C -+#define ODM_REG_DOWNSAM_FACTOR_11N 0xC10 -+#define ODM_REG_RXIQI_MATRIX_11N 0xC14 -+#define ODM_REG_TXIQK_MATRIX_LSB1_11N 0xC4C -+#define ODM_REG_IGI_A_11N 0xC50 -+#define ODM_REG_ANTDIV_PARA2_11N 0xC54 -+#define ODM_REG_IGI_B_11N 0xC58 -+#define ODM_REG_ANTDIV_PARA3_11N 0xC5C -+#define ODM_REG_L1SBD_PD_CH_11N 0XC6C -+#define ODM_REG_BB_PWR_SAV2_11N 0xC70 -+#define ODM_REG_BB_AGC_SET_2_11N 0xc74 -+#define ODM_REG_RX_OFF_11N 0xC7C -+#define ODM_REG_TXIQK_MATRIXA_11N 0xC80 -+#define ODM_REG_TXIQK_MATRIXB_11N 0xC88 -+#define ODM_REG_TXIQK_MATRIXA_LSB2_11N 0xC94 -+#define ODM_REG_TXIQK_MATRIXB_LSB2_11N 0xC9C -+#define ODM_REG_RXIQK_MATRIX_LSB_11N 0xCA0 -+#define ODM_REG_ANTDIV_PARA1_11N 0xCA4 -+#define ODM_REG_SMALL_BANDWIDTH_11N 0xCE4 -+#define ODM_REG_OFDM_FA_TYPE1_11N 0xCF0 -+/* PAGE D */ -+#define ODM_REG_OFDM_FA_RSTD_11N 0xD00 -+#define ODM_REG_BB_RX_ANT_11N 0xD04 -+#define ODM_REG_BB_ATC_11N 0xD2C -+#define ODM_REG_OFDM_FA_TYPE2_11N 0xDA0 -+#define ODM_REG_OFDM_FA_TYPE3_11N 0xDA4 -+#define ODM_REG_OFDM_FA_TYPE4_11N 0xDA8 -+#define ODM_REG_RPT_11N 0xDF4 -+/* PAGE E */ -+#define ODM_REG_TXAGC_A_6_18_11N 0xE00 -+#define ODM_REG_TXAGC_A_24_54_11N 0xE04 -+#define ODM_REG_TXAGC_A_1_MCS32_11N 0xE08 -+#define ODM_REG_TXAGC_A_MCS0_3_11N 0xE10 -+#define ODM_REG_TXAGC_A_MCS4_7_11N 0xE14 -+#define ODM_REG_TXAGC_A_MCS8_11_11N 0xE18 -+#define ODM_REG_TXAGC_A_MCS12_15_11N 0xE1C -+#define ODM_REG_EDCCA_DCNF_11N 0xE24 -+#define ODM_REG_TAP_UPD_97F 0xE24 -+#define ODM_REG_FPGA0_IQK_11N 0xE28 -+#define ODM_REG_PAGE_B1_97F 0xE28 -+#define ODM_REG_TXIQK_TONE_A_11N 0xE30 -+#define ODM_REG_RXIQK_TONE_A_11N 0xE34 -+#define ODM_REG_TXIQK_PI_A_11N 0xE38 -+#define ODM_REG_RXIQK_PI_A_11N 0xE3C -+#define ODM_REG_TXIQK_11N 0xE40 -+#define ODM_REG_RXIQK_11N 0xE44 -+#define ODM_REG_IQK_AGC_PTS_11N 0xE48 -+#define ODM_REG_IQK_AGC_RSP_11N 0xE4C -+#define ODM_REG_BLUETOOTH_11N 0xE6C -+#define ODM_REG_RX_WAIT_CCA_11N 0xE70 -+#define ODM_REG_TX_CCK_RFON_11N 0xE74 -+#define ODM_REG_TX_CCK_BBON_11N 0xE78 -+#define ODM_REG_OFDM_RFON_11N 0xE7C -+#define ODM_REG_OFDM_BBON_11N 0xE80 -+#define ODM_REG_TX2RX_11N 0xE84 -+#define ODM_REG_TX2TX_11N 0xE88 -+#define ODM_REG_RX_CCK_11N 0xE8C -+#define ODM_REG_RX_OFDM_11N 0xED0 -+#define ODM_REG_RX_WAIT_RIFS_11N 0xED4 -+#define ODM_REG_RX2RX_11N 0xED8 -+#define ODM_REG_STANDBY_11N 0xEDC -+#define ODM_REG_SLEEP_11N 0xEE0 -+#define ODM_REG_PMPD_ANAEN_11N 0xEEC -+/* PAGE F */ -+#define ODM_REG_PAGE_F_RST_11N 0xF14 -+#define ODM_REG_IGI_C_11N 0xF84 -+#define ODM_REG_IGI_D_11N 0xF88 -+#define ODM_REG_CCK_CRC32_ERROR_CNT_11N 0xF84 -+#define ODM_REG_CCK_CRC32_OK_CNT_11N 0xF88 -+#define ODM_REG_HT_CRC32_CNT_11N 0xF90 -+#define ODM_REG_OFDM_CRC32_CNT_11N 0xF94 -+#define ODM_REG_HT_CRC32_CNT_11N_AGG 0xFB8 -+ -+/* @2 MAC REG LIST */ -+#define ODM_REG_BB_RST_11N 0x02 -+#define ODM_REG_ANTSEL_PIN_11N 0x4C -+#define ODM_REG_EARLY_MODE_11N 0x4D0 -+#define ODM_REG_RSSI_MONITOR_11N 0x4FE -+#define ODM_REG_EDCA_VO_11N 0x500 -+#define ODM_REG_EDCA_VI_11N 0x504 -+#define ODM_REG_EDCA_BE_11N 0x508 -+#define ODM_REG_EDCA_BK_11N 0x50C -+#define ODM_REG_TXPAUSE_11N 0x522 -+#define ODM_REG_RESP_TX_11N 0x6D8 -+#define ODM_REG_ANT_TRAIN_PARA1_11N 0x7b0 -+#define ODM_REG_ANT_TRAIN_PARA2_11N 0x7b4 -+ -+ -+/* @DIG Related */ -+#define ODM_BIT_IGI_11N 0x0000007F -+#define ODM_BIT_CCK_RPT_FORMAT_11N BIT(9) -+#define ODM_BIT_BB_RX_PATH_11N 0xF -+#define ODM_BIT_BB_TX_PATH_11N 0xF -+#define ODM_BIT_BB_ATC_11N BIT(11) -+#endif -+ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_regtable.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_regtable.h -new file mode 100644 -index 000000000..cf2226c3b ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_regtable.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_regtable.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_regtable.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_regtable.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_regtable.h 2021-03-07 18:16:17.065956573 +0200 @@ -0,0 +1,849 @@ +#define R_0x0 0x0 +#define R_0x00 0x00 @@ -256475,11 +253291,9 @@ index 000000000..cf2226c3b +#define RF_0xee 0xee +#define RF_0xef 0xef +#define RF_0xf5 0xf5 -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_rssi_monitor.c linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_rssi_monitor.c -new file mode 100644 -index 000000000..0d5e41766 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_rssi_monitor.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_rssi_monitor.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_rssi_monitor.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_rssi_monitor.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_rssi_monitor.c 2021-03-07 18:16:17.065956573 +0200 @@ -0,0 +1,170 @@ +/****************************************************************************** + * @@ -256651,11 +253465,9 @@ index 000000000..0d5e41766 +} + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_rssi_monitor.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_rssi_monitor.h -new file mode 100644 -index 000000000..ac997e326 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_rssi_monitor.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_rssi_monitor.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_rssi_monitor.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_rssi_monitor.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_rssi_monitor.h 2021-03-07 18:16:17.065956573 +0200 @@ -0,0 +1,55 @@ +/****************************************************************************** + * @@ -256712,11 +253524,9 @@ index 000000000..ac997e326 +void phydm_rssi_monitor_init(void *dm_void); + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_smt_ant.c linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_smt_ant.c -new file mode 100644 -index 000000000..8e805b3ce ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_smt_ant.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_smt_ant.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_smt_ant.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_smt_ant.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_smt_ant.c 2021-03-07 18:16:17.065956573 +0200 @@ -0,0 +1,2277 @@ +/****************************************************************************** + * @@ -258995,11 +255805,9 @@ index 000000000..8e805b3ce + } +} +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_smt_ant.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_smt_ant.h -new file mode 100644 -index 000000000..3a408c4c6 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_smt_ant.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_smt_ant.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_smt_ant.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_smt_ant.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_smt_ant.h 2021-03-07 18:16:17.065956573 +0200 @@ -0,0 +1,210 @@ +/****************************************************************************** + * @@ -259211,12 +256019,10 @@ index 000000000..3a408c4c6 +void phydm_smt_ant_init(void *dm_void); +#endif /*@#if (defined(CONFIG_SMART_ANTENNA))*/ +#endif -\ No newline at end of file -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_soml.c linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_soml.c -new file mode 100644 -index 000000000..35507e3f4 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_soml.c +\ Ingen nyrad vid filslut +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_soml.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_soml.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_soml.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_soml.c 2021-03-07 18:16:17.065956573 +0200 @@ -0,0 +1,1111 @@ +/****************************************************************************** + * @@ -260329,11 +257135,9 @@ index 000000000..35507e3f4 + } +#endif +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_soml.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_soml.h -new file mode 100644 -index 000000000..2d5fbc31a ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_soml.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_soml.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_soml.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_soml.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_soml.h 2021-03-07 18:16:17.065956573 +0200 @@ -0,0 +1,185 @@ +/****************************************************************************** + * @@ -260520,11 +257324,9 @@ index 000000000..2d5fbc31a +#endif +void phydm_init_soft_ml_setting(void *dm_void); +#endif /*@#ifndef __PHYDMSOML_H__*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_types.h linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_types.h -new file mode 100644 -index 000000000..a13f506b0 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/phydm_types.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_types.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_types.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_types.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/phydm_types.h 2021-03-07 18:16:17.065956573 +0200 @@ -0,0 +1,330 @@ +/****************************************************************************** + * @@ -260856,11 +257658,9 @@ index 000000000..a13f506b0 +#define MASKL3BYTES 0x00ffffff + +#endif /* __ODM_TYPES_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_bb.c linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_bb.c -new file mode 100644 -index 000000000..0d2cb51c0 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_bb.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_bb.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_bb.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_bb.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_bb.c 2021-03-07 18:16:17.066956620 +0200 @@ -0,0 +1,1469 @@ +/****************************************************************************** + * @@ -262331,11 +259131,9 @@ index 000000000..0d2cb51c0 + +#endif /* end of HWIMG_SUPPORT*/ + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_bb.h linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_bb.h -new file mode 100644 -index 000000000..aca9f019f ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_bb.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_bb.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_bb.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_bb.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_bb.h 2021-03-07 18:16:17.066956620 +0200 @@ -0,0 +1,107 @@ +/****************************************************************************** + * @@ -262444,11 +259242,9 @@ index 000000000..aca9f019f +#endif +#endif /* end of HWIMG_SUPPORT*/ + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_mac.c linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_mac.c -new file mode 100644 -index 000000000..febfa8010 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_mac.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_mac.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_mac.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_mac.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_mac.c 2021-03-07 18:16:17.066956620 +0200 @@ -0,0 +1,301 @@ +/****************************************************************************** + * @@ -262751,11 +259547,9 @@ index 000000000..febfa8010 + +#endif /* end of HWIMG_SUPPORT*/ + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_mac.h linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_mac.h -new file mode 100644 -index 000000000..2fe4f20e9 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_mac.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_mac.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_mac.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_mac.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_mac.h 2021-03-07 18:16:17.066956620 +0200 @@ -0,0 +1,33 @@ +/****************************************************************************** + * @@ -262790,11 +259584,9 @@ index 000000000..2fe4f20e9 +#endif +#endif /* end of HWIMG_SUPPORT*/ + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_rf.c linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_rf.c -new file mode 100644 -index 000000000..02f64522d ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_rf.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_rf.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_rf.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_rf.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_rf.c 2021-03-07 18:16:17.066956620 +0200 @@ -0,0 +1,3848 @@ +/****************************************************************************** + * @@ -266644,11 +263436,9 @@ index 000000000..02f64522d + +#endif /* end of HWIMG_SUPPORT*/ + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_rf.h linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_rf.h -new file mode 100644 -index 000000000..20ba73357 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_rf.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_rf.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_rf.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_rf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_rf.h 2021-03-07 18:16:17.066956620 +0200 @@ -0,0 +1,124 @@ +/****************************************************************************** + * @@ -266774,11 +263564,9 @@ index 000000000..20ba73357 +#endif +#endif /* end of HWIMG_SUPPORT*/ + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_regconfig8812a.c linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_regconfig8812a.c -new file mode 100644 -index 000000000..83362e539 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_regconfig8812a.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_regconfig8812a.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_regconfig8812a.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_regconfig8812a.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_regconfig8812a.c 2021-03-07 18:16:17.066956620 +0200 @@ -0,0 +1,149 @@ +/****************************************************************************** + * @@ -266929,11 +263717,9 @@ index 000000000..83362e539 + enum rf_path RF_PATH, u32 reg_addr) {} + +#endif /* #if (RTL8812A_SUPPORT == 1) */ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_regconfig8812a.h linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_regconfig8812a.h -new file mode 100644 -index 000000000..60a24ca29 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_regconfig8812a.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_regconfig8812a.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_regconfig8812a.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_regconfig8812a.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_regconfig8812a.h 2021-03-07 18:16:17.066956620 +0200 @@ -0,0 +1,44 @@ +/****************************************************************************** + * @@ -266979,11 +263765,9 @@ index 000000000..60a24ca29 + +#endif +#endif /* end of SUPPORT */ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_rtl8812a.c linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_rtl8812a.c -new file mode 100644 -index 000000000..192d776bb ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_rtl8812a.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_rtl8812a.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_rtl8812a.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_rtl8812a.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_rtl8812a.c 2021-03-07 18:16:17.066956620 +0200 @@ -0,0 +1,113 @@ +/****************************************************************************** + * @@ -267098,11 +263882,9 @@ index 000000000..192d776bb +} + +#endif /* #if (RTL8812A_SUPPORT == 1) */ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_rtl8812a.h linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_rtl8812a.h -new file mode 100644 -index 000000000..1738351ef ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_rtl8812a.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_rtl8812a.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_rtl8812a.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_rtl8812a.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_rtl8812a.h 2021-03-07 18:16:17.066956620 +0200 @@ -0,0 +1,27 @@ +/****************************************************************************** + * @@ -267131,11 +263913,9 @@ index 000000000..1738351ef +void phydm_hwsetting_8812a(struct dm_struct *dm); + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/version_rtl8812a.h linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/version_rtl8812a.h -new file mode 100644 -index 000000000..c9a50ab32 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8812a/version_rtl8812a.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/version_rtl8812a.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8812a/version_rtl8812a.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/version_rtl8812a.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8812a/version_rtl8812a.h 2021-03-07 18:16:17.066956620 +0200 @@ -0,0 +1,24 @@ +/****************************************************************************** + * @@ -267161,11 +263941,9 @@ index 000000000..c9a50ab32 +#define RELEASE_DATE_8812A 20150920 +#define COMMIT_BY_8812A "BB_LUKE" +#define RELEASE_VERSION_8812A 57 -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/hal8814areg_odm.h linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/hal8814areg_odm.h -new file mode 100644 -index 000000000..1cd40304a ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/hal8814areg_odm.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/hal8814areg_odm.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/hal8814areg_odm.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/hal8814areg_odm.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/hal8814areg_odm.h 2021-03-07 18:16:17.066956620 +0200 @@ -0,0 +1,47 @@ +/****************************************************************************** + * @@ -267214,11 +263992,9 @@ index 000000000..1cd40304a + +#endif + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_bb.c linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_bb.c -new file mode 100644 -index 000000000..181b88a85 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_bb.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_bb.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_bb.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_bb.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_bb.c 2021-03-07 18:16:17.067956667 +0200 @@ -0,0 +1,4308 @@ +/****************************************************************************** + * @@ -271528,11 +268304,9 @@ index 000000000..181b88a85 + +#endif /* end of HWIMG_SUPPORT*/ + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_bb.h linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_bb.h -new file mode 100644 -index 000000000..949b6f978 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_bb.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_bb.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_bb.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_bb.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_bb.h 2021-03-07 18:16:17.067956667 +0200 @@ -0,0 +1,99 @@ +/****************************************************************************** +* @@ -271633,11 +268407,9 @@ index 000000000..949b6f978 +#endif +#endif /* end of HWIMG_SUPPORT*/ + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_fw.h linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_fw.h -new file mode 100644 -index 000000000..3f8de123d ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_fw.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_fw.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_fw.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_fw.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_fw.h 2021-03-07 18:16:17.067956667 +0200 @@ -0,0 +1,56 @@ +/****************************************************************************** +* @@ -271695,11 +268467,9 @@ index 000000000..3f8de123d +#endif +#endif // end of HWIMG_SUPPORT + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_mac.c linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_mac.c -new file mode 100644 -index 000000000..0d5867028 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_mac.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_mac.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_mac.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_mac.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_mac.c 2021-03-07 18:16:17.067956667 +0200 @@ -0,0 +1,325 @@ +/****************************************************************************** + * @@ -272026,11 +268796,9 @@ index 000000000..0d5867028 + +#endif /* end of HWIMG_SUPPORT*/ + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_mac.h linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_mac.h -new file mode 100644 -index 000000000..94f6a2daf ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_mac.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_mac.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_mac.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_mac.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_mac.h 2021-03-07 18:16:17.067956667 +0200 @@ -0,0 +1,39 @@ +/****************************************************************************** +* @@ -272071,11 +268839,9 @@ index 000000000..94f6a2daf +#endif +#endif /* end of HWIMG_SUPPORT*/ + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_rf.c linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_rf.c -new file mode 100644 -index 000000000..c7225cd93 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_rf.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_rf.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_rf.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_rf.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_rf.c 2021-03-07 18:16:17.067956667 +0200 @@ -0,0 +1,8838 @@ +/****************************************************************************** + * @@ -280915,11 +277681,9 @@ index 000000000..c7225cd93 + +#endif /* end of HWIMG_SUPPORT*/ + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_rf.h linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_rf.h -new file mode 100644 -index 000000000..27707510e ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_rf.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_rf.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_rf.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_rf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_rf.h 2021-03-07 18:16:17.067956667 +0200 @@ -0,0 +1,149 @@ +/****************************************************************************** +* @@ -281070,11 +277834,9 @@ index 000000000..27707510e +#endif +#endif /* end of HWIMG_SUPPORT*/ + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap.c linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap.c -new file mode 100644 -index 000000000..948f91963 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap.c 2021-03-07 18:16:17.068956715 +0200 @@ -0,0 +1,1754 @@ +/****************************************************************************** + * @@ -282830,11 +279592,9 @@ index 000000000..948f91963 +#endif + + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap.h linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap.h -new file mode 100644 -index 000000000..cbb1ced95 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap.h 2021-03-07 18:16:17.068956715 +0200 @@ -0,0 +1,164 @@ +/****************************************************************************** + * @@ -283000,11 +279760,9 @@ index 000000000..cbb1ced95 + +#endif // #ifndef __HAL_PHY_RF_8814A_H__ + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_win.c linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_win.c -new file mode 100644 -index 000000000..eb91c4d8a ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_win.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_win.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_win.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_win.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_win.c 2021-03-07 18:16:17.068956715 +0200 @@ -0,0 +1,528 @@ +/****************************************************************************** + * @@ -283534,11 +280292,9 @@ index 000000000..eb91c4d8a + IN BOOLEAN bReCovery + ){} +#endif /* (RTL8814A_SUPPORT == 0)*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_win.h linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_win.h -new file mode 100644 -index 000000000..658d6f063 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_win.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_win.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_win.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_win.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_win.h 2021-03-07 18:16:17.068956715 +0200 @@ -0,0 +1,106 @@ +/****************************************************************************** + * @@ -283646,11 +280402,9 @@ index 000000000..658d6f063 + +#endif // #ifndef __HAL_PHY_RF_8188E_H__ + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_regconfig8814a.c linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_regconfig8814a.c -new file mode 100644 -index 000000000..2e3f20622 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_regconfig8814a.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_regconfig8814a.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_regconfig8814a.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_regconfig8814a.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_regconfig8814a.c 2021-03-07 18:16:17.068956715 +0200 @@ -0,0 +1,219 @@ +/****************************************************************************** + * @@ -283871,11 +280625,9 @@ index 000000000..2e3f20622 +} +#endif + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_regconfig8814a.h linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_regconfig8814a.h -new file mode 100644 -index 000000000..bc3f9434e ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_regconfig8814a.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_regconfig8814a.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_regconfig8814a.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_regconfig8814a.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_regconfig8814a.h 2021-03-07 18:16:17.068956715 +0200 @@ -0,0 +1,109 @@ +/****************************************************************************** + * @@ -283986,11 +280738,9 @@ index 000000000..bc3f9434e +#endif +#endif // end of SUPPORT + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_rtl8814a.c linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_rtl8814a.c -new file mode 100644 -index 000000000..885e06336 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_rtl8814a.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_rtl8814a.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_rtl8814a.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_rtl8814a.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_rtl8814a.c 2021-03-07 18:16:17.068956715 +0200 @@ -0,0 +1,503 @@ +/****************************************************************************** + * @@ -284495,11 +281245,9 @@ index 000000000..885e06336 + + + -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_rtl8814a.h linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_rtl8814a.h -new file mode 100644 -index 000000000..a7ff6757d ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_rtl8814a.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_rtl8814a.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_rtl8814a.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_rtl8814a.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_rtl8814a.h 2021-03-07 18:16:17.068956715 +0200 @@ -0,0 +1,78 @@ +/****************************************************************************** + * @@ -284579,11 +281327,9 @@ index 000000000..a7ff6757d + ); + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/version_rtl8814a.h linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/version_rtl8814a.h -new file mode 100644 -index 000000000..e9c28bfb7 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8814a/version_rtl8814a.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/version_rtl8814a.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/version_rtl8814a.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/version_rtl8814a.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8814a/version_rtl8814a.h 2021-03-07 18:16:17.068956715 +0200 @@ -0,0 +1,10 @@ +/*RTL8814A PHY Parameters*/ +/* @@ -284595,11 +281341,9 @@ index 000000000..e9c28bfb7 +#define RELEASE_DATE_8814A 20150908 +#define COMMIT_BY_8814A "BB_LUKE" +#define RELEASE_VERSION_8814A 81 -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_bb.c linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_bb.c -new file mode 100644 -index 000000000..0dc7ab6e1 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_bb.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_bb.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_bb.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_bb.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_bb.c 2021-03-07 18:16:17.068956715 +0200 @@ -0,0 +1,923 @@ +/****************************************************************************** + * @@ -285524,11 +282268,9 @@ index 000000000..0dc7ab6e1 + + +#endif /* end of HWIMG_SUPPORT*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_bb.h linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_bb.h -new file mode 100644 -index 000000000..791b7d19d ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_bb.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_bb.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_bb.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_bb.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_bb.h 2021-03-07 18:16:17.068956715 +0200 @@ -0,0 +1,83 @@ +/****************************************************************************** + * @@ -285613,11 +282355,9 @@ index 000000000..791b7d19d + +#endif +#endif /* end of HWIMG_SUPPORT*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_mac.c linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_mac.c -new file mode 100644 -index 000000000..b93be49b6 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_mac.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_mac.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_mac.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_mac.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_mac.c 2021-03-07 18:16:17.068956715 +0200 @@ -0,0 +1,279 @@ +/****************************************************************************** + * @@ -285898,11 +282638,9 @@ index 000000000..b93be49b6 +} + +#endif /* end of HWIMG_SUPPORT*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_mac.h linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_mac.h -new file mode 100644 -index 000000000..35665a4d1 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_mac.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_mac.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_mac.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_mac.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_mac.h 2021-03-07 18:16:17.068956715 +0200 @@ -0,0 +1,33 @@ +/****************************************************************************** + * @@ -285937,11 +282675,9 @@ index 000000000..35665a4d1 + +#endif +#endif /* end of HWIMG_SUPPORT*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_rf.c linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_rf.c -new file mode 100644 -index 000000000..05b004bd4 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_rf.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_rf.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_rf.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_rf.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_rf.c 2021-03-07 18:16:17.069956761 +0200 @@ -0,0 +1,5457 @@ +/****************************************************************************** + * @@ -291400,11 +288136,9 @@ index 000000000..05b004bd4 +} + +#endif /* end of HWIMG_SUPPORT*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_rf.h linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_rf.h -new file mode 100644 -index 000000000..e630f7cb5 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_rf.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_rf.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_rf.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_rf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_rf.h 2021-03-07 18:16:17.069956761 +0200 @@ -0,0 +1,143 @@ +/****************************************************************************** + * @@ -291549,11 +288283,9 @@ index 000000000..e630f7cb5 + +#endif +#endif /* end of HWIMG_SUPPORT*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_regconfig8821a.c linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_regconfig8821a.c -new file mode 100644 -index 000000000..aa96ac7fc ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_regconfig8821a.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_regconfig8821a.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_regconfig8821a.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_regconfig8821a.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_regconfig8821a.c 2021-03-07 18:16:17.069956761 +0200 @@ -0,0 +1,206 @@ +/****************************************************************************** + * @@ -291761,11 +288493,9 @@ index 000000000..aa96ac7fc +} + +#endif /* #if (RTL8821A_SUPPORT == 1)*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_regconfig8821a.h linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_regconfig8821a.h -new file mode 100644 -index 000000000..cf5eeeb19 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_regconfig8821a.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_regconfig8821a.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_regconfig8821a.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_regconfig8821a.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_regconfig8821a.h 2021-03-07 18:16:17.069956761 +0200 @@ -0,0 +1,90 @@ +/****************************************************************************** + * @@ -291857,11 +288587,9 @@ index 000000000..cf5eeeb19 + +#endif +#endif /* end of SUPPORT */ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_rtl8821a.c linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_rtl8821a.c -new file mode 100644 -index 000000000..5de0754da ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_rtl8821a.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_rtl8821a.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_rtl8821a.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_rtl8821a.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_rtl8821a.c 2021-03-07 18:16:17.069956761 +0200 @@ -0,0 +1,129 @@ +/****************************************************************************** + * @@ -291992,11 +288720,9 @@ index 000000000..5de0754da +} + +#endif /* #if (RTL8821A_SUPPORT == 1) */ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_rtl8821a.h linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_rtl8821a.h -new file mode 100644 -index 000000000..2886fdc56 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_rtl8821a.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_rtl8821a.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_rtl8821a.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_rtl8821a.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_rtl8821a.h 2021-03-07 18:16:17.069956761 +0200 @@ -0,0 +1,31 @@ +/****************************************************************************** + * @@ -292029,11 +288755,9 @@ index 000000000..2886fdc56 +); + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/version_rtl8821a.h linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/version_rtl8821a.h -new file mode 100644 -index 000000000..63b4ec971 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/rtl8821a/version_rtl8821a.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/version_rtl8821a.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8821a/version_rtl8821a.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/version_rtl8821a.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/rtl8821a/version_rtl8821a.h 2021-03-07 18:16:17.069956761 +0200 @@ -0,0 +1,24 @@ +/****************************************************************************** + * @@ -292059,11 +288783,9 @@ index 000000000..63b4ec971 +#define RELEASE_DATE_8821A 20150920 +#define COMMIT_BY_8821A "BB_LUKE" +#define RELEASE_VERSION_8821A 59 -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/sd4_phydm_2_kernel.mk linux-5.8/3rdparty/rtl8812au/hal/phydm/sd4_phydm_2_kernel.mk -new file mode 100644 -index 000000000..f11c6ac90 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/sd4_phydm_2_kernel.mk +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/sd4_phydm_2_kernel.mk linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/sd4_phydm_2_kernel.mk +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/sd4_phydm_2_kernel.mk 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/sd4_phydm_2_kernel.mk 2021-03-07 18:16:17.069956761 +0200 @@ -0,0 +1,188 @@ +EXTRA_CFLAGS += -I$(src)/hal/phydm + @@ -292253,11 +288975,9 @@ index 000000000..f11c6ac90 + hal/phydm/$(RTL871X)/phydm_hal_api8198f.o\ + hal/phydm/$(RTL871X)/phydm_regconfig8198f.o +endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/halcomtxbf.c linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/halcomtxbf.c -new file mode 100644 -index 000000000..ae45a5b1a ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/halcomtxbf.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/halcomtxbf.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/txbf/halcomtxbf.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/halcomtxbf.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/txbf/halcomtxbf.c 2021-03-07 18:16:17.069956761 +0200 @@ -0,0 +1,520 @@ +/****************************************************************************** + * @@ -292779,11 +289499,9 @@ index 000000000..ae45a5b1a +#endif + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/halcomtxbf.h linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/halcomtxbf.h -new file mode 100644 -index 000000000..5ad303394 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/halcomtxbf.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/halcomtxbf.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/txbf/halcomtxbf.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/halcomtxbf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/txbf/halcomtxbf.h 2021-03-07 18:16:17.069956761 +0200 @@ -0,0 +1,183 @@ +/****************************************************************************** + * @@ -292968,11 +289686,9 @@ index 000000000..5ad303394 +#endif + +#endif /* @#ifndef __HAL_COM_TXBF_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8192e.c linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8192e.c -new file mode 100644 -index 000000000..daac3e58a ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8192e.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8192e.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8192e.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8192e.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8192e.c 2021-03-07 18:16:17.069956761 +0200 @@ -0,0 +1,384 @@ +/****************************************************************************** + * @@ -293358,11 +290074,9 @@ index 000000000..daac3e58a +#endif /* @#if (RTL8192E_SUPPORT == 1)*/ + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8192e.h linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8192e.h -new file mode 100644 -index 000000000..9b0c8321f ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8192e.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8192e.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8192e.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8192e.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8192e.h 2021-03-07 18:16:17.069956761 +0200 @@ -0,0 +1,71 @@ +/****************************************************************************** + * @@ -293435,11 +290149,9 @@ index 000000000..9b0c8321f +#endif + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8814a.c linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8814a.c -new file mode 100644 -index 000000000..7ad6ca909 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8814a.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8814a.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8814a.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8814a.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8814a.c 2021-03-07 18:16:17.069956761 +0200 @@ -0,0 +1,675 @@ +/****************************************************************************** + * @@ -294116,11 +290828,9 @@ index 000000000..7ad6ca909 +#endif /* @(RTL8814A_SUPPORT == 1)*/ + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8814a.h linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8814a.h -new file mode 100644 -index 000000000..61b33bbfb ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8814a.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8814a.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8814a.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8814a.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8814a.h 2021-03-07 18:16:17.069956761 +0200 @@ -0,0 +1,77 @@ +/****************************************************************************** + * @@ -294199,11 +290909,9 @@ index 000000000..61b33bbfb +#endif + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8822b.c linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8822b.c -new file mode 100644 -index 000000000..f25912a5e ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8822b.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8822b.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8822b.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8822b.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8822b.c 2021-03-07 18:16:17.069956761 +0200 @@ -0,0 +1,1087 @@ +/****************************************************************************** + * @@ -295292,11 +292000,9 @@ index 000000000..f25912a5e +} +#endif +#endif /* @(RTL8822B_SUPPORT == 1)*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8822b.h linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8822b.h -new file mode 100644 -index 000000000..552fba2a7 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8822b.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8822b.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8822b.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8822b.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8822b.h 2021-03-07 18:16:17.069956761 +0200 @@ -0,0 +1,78 @@ +/****************************************************************************** + * @@ -295376,11 +292082,9 @@ index 000000000..552fba2a7 + +#endif +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfinterface.c linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfinterface.c -new file mode 100644 -index 000000000..c125fecad ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfinterface.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfinterface.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfinterface.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfinterface.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfinterface.c 2021-03-07 18:16:17.069956761 +0200 @@ -0,0 +1,1484 @@ +/****************************************************************************** + * @@ -296866,11 +293570,9 @@ index 000000000..c125fecad +} + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfinterface.h linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfinterface.h -new file mode 100644 -index 000000000..b97aa349e ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfinterface.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfinterface.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfinterface.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfinterface.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfinterface.h 2021-03-07 18:16:17.069956761 +0200 @@ -0,0 +1,167 @@ +/****************************************************************************** + * @@ -297039,11 +293741,9 @@ index 000000000..b97aa349e +#endif + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfjaguar.c linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfjaguar.c -new file mode 100644 -index 000000000..18a47d4a9 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfjaguar.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfjaguar.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfjaguar.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfjaguar.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfjaguar.c 2021-03-07 18:16:17.070956809 +0200 @@ -0,0 +1,510 @@ +/****************************************************************************** + * @@ -297555,11 +294255,9 @@ index 000000000..18a47d4a9 +#endif + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfjaguar.h linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfjaguar.h -new file mode 100644 -index 000000000..2c9a623ba ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfjaguar.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfjaguar.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfjaguar.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfjaguar.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfjaguar.h 2021-03-07 18:16:17.070956809 +0200 @@ -0,0 +1,78 @@ +/****************************************************************************** + * @@ -297639,11 +294337,9 @@ index 000000000..2c9a623ba +#endif + +#endif /* @#ifndef __HAL_TXBF_JAGUAR_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/phydm_hal_txbf_api.c linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/phydm_hal_txbf_api.c -new file mode 100644 -index 000000000..a7f7e14fb ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/phydm_hal_txbf_api.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/phydm_hal_txbf_api.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/txbf/phydm_hal_txbf_api.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/phydm_hal_txbf_api.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/txbf/phydm_hal_txbf_api.c 2021-03-07 18:16:17.070956809 +0200 @@ -0,0 +1,425 @@ +/****************************************************************************** + * @@ -298070,11 +294766,9 @@ index 000000000..a7f7e14fb +#endif +#endif /*PHYSTS_3RD_TYPE_IC*/ +#endif /*CONFIG_BB_TXBF_API*/ -diff --git linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/phydm_hal_txbf_api.h linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/phydm_hal_txbf_api.h -new file mode 100644 -index 000000000..7755bcaf9 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/phydm/txbf/phydm_hal_txbf_api.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/phydm_hal_txbf_api.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/txbf/phydm_hal_txbf_api.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/phydm_hal_txbf_api.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/phydm/txbf/phydm_hal_txbf_api.h 2021-03-07 18:16:17.070956809 +0200 @@ -0,0 +1,74 @@ +/****************************************************************************** + * @@ -298150,192 +294844,9 @@ index 000000000..7755bcaf9 + +#endif +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/Hal8812PwrSeq.c linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/Hal8812PwrSeq.c -new file mode 100644 -index 000000000..f450325fd ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/Hal8812PwrSeq.c -@@ -0,0 +1,83 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+ -+#include "Hal8812PwrSeq.h" -+#include -+ -+/* -+ drivers should parse below arrays and do the corresponding actions -+*/ -+/* 3 Power on Array */ -+WLAN_PWR_CFG rtl8812_power_on_flow[RTL8812_TRANS_CARDEMU_TO_ACT_STEPS + RTL8812_TRANS_END_STEPS] = { -+ RTL8812_TRANS_CARDEMU_TO_ACT -+ RTL8812_TRANS_END -+}; -+ -+/* 3Radio off GPIO Array */ -+WLAN_PWR_CFG rtl8812_radio_off_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS + RTL8812_TRANS_END_STEPS] = { -+ RTL8812_TRANS_ACT_TO_CARDEMU -+ RTL8812_TRANS_END -+}; -+ -+/* 3Card Disable Array */ -+WLAN_PWR_CFG rtl8812_card_disable_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS + RTL8812_TRANS_CARDEMU_TO_PDN_STEPS + RTL8812_TRANS_END_STEPS] = { -+ RTL8812_TRANS_ACT_TO_CARDEMU -+ RTL8812_TRANS_CARDEMU_TO_CARDDIS -+ RTL8812_TRANS_END -+}; -+ -+/* 3 Card Enable Array */ -+WLAN_PWR_CFG rtl8812_card_enable_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS + RTL8812_TRANS_CARDEMU_TO_PDN_STEPS + RTL8812_TRANS_END_STEPS] = { -+ RTL8812_TRANS_CARDDIS_TO_CARDEMU -+ RTL8812_TRANS_CARDEMU_TO_ACT -+ RTL8812_TRANS_END -+}; -+ -+/* 3Suspend Array */ -+WLAN_PWR_CFG rtl8812_suspend_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS + RTL8812_TRANS_CARDEMU_TO_SUS_STEPS + RTL8812_TRANS_END_STEPS] = { -+ RTL8812_TRANS_ACT_TO_CARDEMU -+ RTL8812_TRANS_CARDEMU_TO_SUS -+ RTL8812_TRANS_END -+}; -+ -+/* 3 Resume Array */ -+WLAN_PWR_CFG rtl8812_resume_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS + RTL8812_TRANS_CARDEMU_TO_SUS_STEPS + RTL8812_TRANS_END_STEPS] = { -+ RTL8812_TRANS_SUS_TO_CARDEMU -+ RTL8812_TRANS_CARDEMU_TO_ACT -+ RTL8812_TRANS_END -+}; -+ -+ -+ -+/* 3HWPDN Array */ -+WLAN_PWR_CFG rtl8812_hwpdn_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS + RTL8812_TRANS_CARDEMU_TO_PDN_STEPS + RTL8812_TRANS_END_STEPS] = { -+ RTL8812_TRANS_ACT_TO_CARDEMU -+ RTL8812_TRANS_CARDEMU_TO_PDN -+ RTL8812_TRANS_END -+}; -+ -+/* 3 Enter LPS */ -+WLAN_PWR_CFG rtl8812_enter_lps_flow[RTL8812_TRANS_ACT_TO_LPS_STEPS + RTL8812_TRANS_END_STEPS] = { -+ /* FW behavior */ -+ RTL8812_TRANS_ACT_TO_LPS -+ RTL8812_TRANS_END -+}; -+ -+/* 3 Leave LPS */ -+WLAN_PWR_CFG rtl8812_leave_lps_flow[RTL8812_TRANS_LPS_TO_ACT_STEPS + RTL8812_TRANS_END_STEPS] = { -+ /* FW behavior */ -+ RTL8812_TRANS_LPS_TO_ACT -+ RTL8812_TRANS_END -+}; -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/Hal8821APwrSeq.c linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/Hal8821APwrSeq.c -new file mode 100644 -index 000000000..2e13733de ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/Hal8821APwrSeq.c -@@ -0,0 +1,86 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) Semiconductor - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+ -+ -+ -+#include "Hal8821APwrSeq.h" -+#include -+ -+ -+/* -+ drivers should parse below arrays and do the corresponding actions -+*/ -+/* 3 Power on Array */ -+WLAN_PWR_CFG rtl8821A_power_on_flow[RTL8821A_TRANS_CARDEMU_TO_ACT_STEPS + RTL8821A_TRANS_END_STEPS] = { -+ RTL8821A_TRANS_CARDEMU_TO_ACT -+ RTL8821A_TRANS_END -+}; -+ -+/* 3Radio off GPIO Array */ -+WLAN_PWR_CFG rtl8821A_radio_off_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8821A_TRANS_END_STEPS] = { -+ RTL8821A_TRANS_ACT_TO_CARDEMU -+ RTL8821A_TRANS_END -+}; -+ -+/* 3Card Disable Array */ -+WLAN_PWR_CFG rtl8821A_card_disable_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8821A_TRANS_CARDEMU_TO_PDN_STEPS + RTL8821A_TRANS_END_STEPS] = { -+ RTL8821A_TRANS_ACT_TO_CARDEMU -+ RTL8821A_TRANS_CARDEMU_TO_CARDDIS -+ RTL8821A_TRANS_END -+}; -+ -+/* 3 Card Enable Array */ -+WLAN_PWR_CFG rtl8821A_card_enable_flow[RTL8821A_TRANS_CARDDIS_TO_CARDEMU_STEPS + RTL8821A_TRANS_CARDEMU_TO_ACT_STEPS + RTL8821A_TRANS_END_STEPS] = { -+ RTL8821A_TRANS_CARDDIS_TO_CARDEMU -+ RTL8821A_TRANS_CARDEMU_TO_ACT -+ RTL8821A_TRANS_END -+}; -+ -+/* 3Suspend Array */ -+WLAN_PWR_CFG rtl8821A_suspend_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8821A_TRANS_CARDEMU_TO_SUS_STEPS + RTL8821A_TRANS_END_STEPS] = { -+ RTL8821A_TRANS_ACT_TO_CARDEMU -+ RTL8821A_TRANS_CARDEMU_TO_SUS -+ RTL8821A_TRANS_END -+}; -+ -+/* 3 Resume Array */ -+WLAN_PWR_CFG rtl8821A_resume_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8821A_TRANS_CARDEMU_TO_SUS_STEPS + RTL8821A_TRANS_END_STEPS] = { -+ RTL8821A_TRANS_SUS_TO_CARDEMU -+ RTL8821A_TRANS_CARDEMU_TO_ACT -+ RTL8821A_TRANS_END -+}; -+ -+ -+ -+/* 3HWPDN Array */ -+WLAN_PWR_CFG rtl8821A_hwpdn_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8821A_TRANS_CARDEMU_TO_PDN_STEPS + RTL8821A_TRANS_END_STEPS] = { -+ RTL8821A_TRANS_ACT_TO_CARDEMU -+ RTL8821A_TRANS_CARDEMU_TO_PDN -+ RTL8821A_TRANS_END -+}; -+ -+/* 3 Enter LPS */ -+WLAN_PWR_CFG rtl8821A_enter_lps_flow[RTL8821A_TRANS_ACT_TO_LPS_STEPS + RTL8821A_TRANS_END_STEPS] = { -+ /* FW behavior */ -+ RTL8821A_TRANS_ACT_TO_LPS -+ RTL8821A_TRANS_END -+}; -+ -+/* 3 Leave LPS */ -+WLAN_PWR_CFG rtl8821A_leave_lps_flow[RTL8821A_TRANS_LPS_TO_ACT_STEPS + RTL8821A_TRANS_END_STEPS] = { -+ /* FW behavior */ -+ RTL8821A_TRANS_LPS_TO_ACT -+ RTL8821A_TRANS_END -+}; -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/hal8812a_fw.c linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/hal8812a_fw.c -new file mode 100644 -index 000000000..388d84452 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/hal8812a_fw.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/hal8812a_fw.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/hal8812a_fw.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/hal8812a_fw.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/hal8812a_fw.c 2021-03-07 18:16:17.074956998 +0200 @@ -0,0 +1,17941 @@ +/****************************************************************************** +* @@ -316278,11 +312789,9 @@ index 000000000..388d84452 +#endif /* end of LOAD_FW_HEADER_FROM_DRIVER */ + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/hal8812a_fw.h linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/hal8812a_fw.h -new file mode 100644 -index 000000000..0a370d534 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/hal8812a_fw.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/hal8812a_fw.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/hal8812a_fw.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/hal8812a_fw.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/hal8812a_fw.h 2021-03-07 18:16:17.074956998 +0200 @@ -0,0 +1,47 @@ +/****************************************************************************** +* @@ -316331,11 +312840,96 @@ index 000000000..0a370d534 + +#endif + -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/hal8821a_fw.c linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/hal8821a_fw.c -new file mode 100644 -index 000000000..40728f7cc ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/hal8821a_fw.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/Hal8812PwrSeq.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/Hal8812PwrSeq.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/Hal8812PwrSeq.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/Hal8812PwrSeq.c 2021-03-07 18:16:17.070956809 +0200 +@@ -0,0 +1,83 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++ ++#include "Hal8812PwrSeq.h" ++#include ++ ++/* ++ drivers should parse below arrays and do the corresponding actions ++*/ ++/* 3 Power on Array */ ++WLAN_PWR_CFG rtl8812_power_on_flow[RTL8812_TRANS_CARDEMU_TO_ACT_STEPS + RTL8812_TRANS_END_STEPS] = { ++ RTL8812_TRANS_CARDEMU_TO_ACT ++ RTL8812_TRANS_END ++}; ++ ++/* 3Radio off GPIO Array */ ++WLAN_PWR_CFG rtl8812_radio_off_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS + RTL8812_TRANS_END_STEPS] = { ++ RTL8812_TRANS_ACT_TO_CARDEMU ++ RTL8812_TRANS_END ++}; ++ ++/* 3Card Disable Array */ ++WLAN_PWR_CFG rtl8812_card_disable_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS + RTL8812_TRANS_CARDEMU_TO_PDN_STEPS + RTL8812_TRANS_END_STEPS] = { ++ RTL8812_TRANS_ACT_TO_CARDEMU ++ RTL8812_TRANS_CARDEMU_TO_CARDDIS ++ RTL8812_TRANS_END ++}; ++ ++/* 3 Card Enable Array */ ++WLAN_PWR_CFG rtl8812_card_enable_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS + RTL8812_TRANS_CARDEMU_TO_PDN_STEPS + RTL8812_TRANS_END_STEPS] = { ++ RTL8812_TRANS_CARDDIS_TO_CARDEMU ++ RTL8812_TRANS_CARDEMU_TO_ACT ++ RTL8812_TRANS_END ++}; ++ ++/* 3Suspend Array */ ++WLAN_PWR_CFG rtl8812_suspend_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS + RTL8812_TRANS_CARDEMU_TO_SUS_STEPS + RTL8812_TRANS_END_STEPS] = { ++ RTL8812_TRANS_ACT_TO_CARDEMU ++ RTL8812_TRANS_CARDEMU_TO_SUS ++ RTL8812_TRANS_END ++}; ++ ++/* 3 Resume Array */ ++WLAN_PWR_CFG rtl8812_resume_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS + RTL8812_TRANS_CARDEMU_TO_SUS_STEPS + RTL8812_TRANS_END_STEPS] = { ++ RTL8812_TRANS_SUS_TO_CARDEMU ++ RTL8812_TRANS_CARDEMU_TO_ACT ++ RTL8812_TRANS_END ++}; ++ ++ ++ ++/* 3HWPDN Array */ ++WLAN_PWR_CFG rtl8812_hwpdn_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS + RTL8812_TRANS_CARDEMU_TO_PDN_STEPS + RTL8812_TRANS_END_STEPS] = { ++ RTL8812_TRANS_ACT_TO_CARDEMU ++ RTL8812_TRANS_CARDEMU_TO_PDN ++ RTL8812_TRANS_END ++}; ++ ++/* 3 Enter LPS */ ++WLAN_PWR_CFG rtl8812_enter_lps_flow[RTL8812_TRANS_ACT_TO_LPS_STEPS + RTL8812_TRANS_END_STEPS] = { ++ /* FW behavior */ ++ RTL8812_TRANS_ACT_TO_LPS ++ RTL8812_TRANS_END ++}; ++ ++/* 3 Leave LPS */ ++WLAN_PWR_CFG rtl8812_leave_lps_flow[RTL8812_TRANS_LPS_TO_ACT_STEPS + RTL8812_TRANS_END_STEPS] = { ++ /* FW behavior */ ++ RTL8812_TRANS_LPS_TO_ACT ++ RTL8812_TRANS_END ++}; +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/hal8821a_fw.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/hal8821a_fw.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/hal8821a_fw.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/hal8821a_fw.c 2021-03-07 18:16:17.078957187 +0200 @@ -0,0 +1,14005 @@ +/****************************************************************************** +* @@ -330342,11 +326936,9 @@ index 000000000..40728f7cc +#endif /* end of LOAD_FW_HEADER_FROM_DRIVER */ + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/hal8821a_fw.h linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/hal8821a_fw.h -new file mode 100644 -index 000000000..16b394f16 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/hal8821a_fw.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/hal8821a_fw.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/hal8821a_fw.h +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/hal8821a_fw.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/hal8821a_fw.h 2021-03-07 18:16:17.078957187 +0200 @@ -0,0 +1,47 @@ +/****************************************************************************** +* @@ -330395,11 +326987,99 @@ index 000000000..16b394f16 + +#endif + -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_cmd.c linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_cmd.c -new file mode 100644 -index 000000000..ecbb397d5 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_cmd.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/Hal8821APwrSeq.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/Hal8821APwrSeq.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/Hal8821APwrSeq.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/Hal8821APwrSeq.c 2021-03-07 18:16:17.070956809 +0200 +@@ -0,0 +1,86 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) Semiconductor - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++ ++ ++ ++#include "Hal8821APwrSeq.h" ++#include ++ ++ ++/* ++ drivers should parse below arrays and do the corresponding actions ++*/ ++/* 3 Power on Array */ ++WLAN_PWR_CFG rtl8821A_power_on_flow[RTL8821A_TRANS_CARDEMU_TO_ACT_STEPS + RTL8821A_TRANS_END_STEPS] = { ++ RTL8821A_TRANS_CARDEMU_TO_ACT ++ RTL8821A_TRANS_END ++}; ++ ++/* 3Radio off GPIO Array */ ++WLAN_PWR_CFG rtl8821A_radio_off_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8821A_TRANS_END_STEPS] = { ++ RTL8821A_TRANS_ACT_TO_CARDEMU ++ RTL8821A_TRANS_END ++}; ++ ++/* 3Card Disable Array */ ++WLAN_PWR_CFG rtl8821A_card_disable_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8821A_TRANS_CARDEMU_TO_PDN_STEPS + RTL8821A_TRANS_END_STEPS] = { ++ RTL8821A_TRANS_ACT_TO_CARDEMU ++ RTL8821A_TRANS_CARDEMU_TO_CARDDIS ++ RTL8821A_TRANS_END ++}; ++ ++/* 3 Card Enable Array */ ++WLAN_PWR_CFG rtl8821A_card_enable_flow[RTL8821A_TRANS_CARDDIS_TO_CARDEMU_STEPS + RTL8821A_TRANS_CARDEMU_TO_ACT_STEPS + RTL8821A_TRANS_END_STEPS] = { ++ RTL8821A_TRANS_CARDDIS_TO_CARDEMU ++ RTL8821A_TRANS_CARDEMU_TO_ACT ++ RTL8821A_TRANS_END ++}; ++ ++/* 3Suspend Array */ ++WLAN_PWR_CFG rtl8821A_suspend_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8821A_TRANS_CARDEMU_TO_SUS_STEPS + RTL8821A_TRANS_END_STEPS] = { ++ RTL8821A_TRANS_ACT_TO_CARDEMU ++ RTL8821A_TRANS_CARDEMU_TO_SUS ++ RTL8821A_TRANS_END ++}; ++ ++/* 3 Resume Array */ ++WLAN_PWR_CFG rtl8821A_resume_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8821A_TRANS_CARDEMU_TO_SUS_STEPS + RTL8821A_TRANS_END_STEPS] = { ++ RTL8821A_TRANS_SUS_TO_CARDEMU ++ RTL8821A_TRANS_CARDEMU_TO_ACT ++ RTL8821A_TRANS_END ++}; ++ ++ ++ ++/* 3HWPDN Array */ ++WLAN_PWR_CFG rtl8821A_hwpdn_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8821A_TRANS_CARDEMU_TO_PDN_STEPS + RTL8821A_TRANS_END_STEPS] = { ++ RTL8821A_TRANS_ACT_TO_CARDEMU ++ RTL8821A_TRANS_CARDEMU_TO_PDN ++ RTL8821A_TRANS_END ++}; ++ ++/* 3 Enter LPS */ ++WLAN_PWR_CFG rtl8821A_enter_lps_flow[RTL8821A_TRANS_ACT_TO_LPS_STEPS + RTL8821A_TRANS_END_STEPS] = { ++ /* FW behavior */ ++ RTL8821A_TRANS_ACT_TO_LPS ++ RTL8821A_TRANS_END ++}; ++ ++/* 3 Leave LPS */ ++WLAN_PWR_CFG rtl8821A_leave_lps_flow[RTL8821A_TRANS_LPS_TO_ACT_STEPS + RTL8821A_TRANS_END_STEPS] = { ++ /* FW behavior */ ++ RTL8821A_TRANS_LPS_TO_ACT ++ RTL8821A_TRANS_END ++}; +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_cmd.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_cmd.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_cmd.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_cmd.c 2021-03-07 18:16:17.079957235 +0200 @@ -0,0 +1,860 @@ +/****************************************************************************** + * @@ -331261,11 +327941,9 @@ index 000000000..ecbb397d5 +} + +#endif /* CONFIG_BT_COEXIST */ -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_dm.c linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_dm.c -new file mode 100644 -index 000000000..56c7cc750 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_dm.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_dm.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_dm.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_dm.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_dm.c 2021-03-07 18:16:17.079957235 +0200 @@ -0,0 +1,360 @@ +/****************************************************************************** + * @@ -331627,11 +328305,9 @@ index 000000000..56c7cc750 + /* _rtw_spinlock_free(&pHalData->odm_stainfo_lock); */ + odm_cancel_all_timers(podmpriv); +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_hal_init.c linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_hal_init.c -new file mode 100644 -index 000000000..4a21818b7 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_hal_init.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_hal_init.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_hal_init.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_hal_init.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_hal_init.c 2021-03-07 18:16:17.079957235 +0200 @@ -0,0 +1,5777 @@ +/****************************************************************************** + * @@ -337410,12 +334086,10 @@ index 000000000..4a21818b7 + pHalFunc->fw_dl = &FirmwareDownload8812; + pHalFunc->hal_get_tx_buff_rsvd_page_num = &GetTxBufferRsvdPageNum8812; +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_phycfg.c linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_phycfg.c -new file mode 100644 -index 000000000..4fb1b8cef ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_phycfg.c -@@ -0,0 +1,2041 @@ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_phycfg.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_phycfg.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_phycfg.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_phycfg.c 2021-03-07 18:16:17.080957282 +0200 +@@ -0,0 +1,2045 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -339216,9 +335890,11 @@ index 000000000..4fb1b8cef + /* fc_area */ + if (36 <= channelToSW && channelToSW <= 48) + phy_set_bb_reg(pAdapter, rFc_area_Jaguar, 0x1ffe0000, 0x494); -+ else if (50 <= channelToSW && channelToSW <= 64) ++ else if (15 <= channelToSW && channelToSW <= 35) ++ phy_set_bb_reg(pAdapter, rFc_area_Jaguar, 0x1ffe0000, 0x494); ++ else if (50 <= channelToSW && channelToSW <= 80) + phy_set_bb_reg(pAdapter, rFc_area_Jaguar, 0x1ffe0000, 0x453); -+ else if (100 <= channelToSW && channelToSW <= 116) ++ else if (82 <= channelToSW && channelToSW <= 116) + phy_set_bb_reg(pAdapter, rFc_area_Jaguar, 0x1ffe0000, 0x452); + else if (118 <= channelToSW) + phy_set_bb_reg(pAdapter, rFc_area_Jaguar, 0x1ffe0000, 0x412); @@ -339227,9 +335903,11 @@ index 000000000..4fb1b8cef + + for (eRFPath = 0; eRFPath < pHalData->NumTotalRFPath; eRFPath++) { + /* RF_MOD_AG */ -+ if (36 <= channelToSW && channelToSW <= 64) ++ if (36 <= channelToSW && channelToSW <= 80) + phy_set_rf_reg(pAdapter, eRFPath, RF_CHNLBW_Jaguar, BIT18 | BIT17 | BIT16 | BIT9 | BIT8, 0x101); /* 5'b00101); */ -+ else if (100 <= channelToSW && channelToSW <= 140) ++ else if (15 <= channelToSW && channelToSW <= 35) ++ phy_set_rf_reg(pAdapter, eRFPath, RF_CHNLBW_Jaguar, BIT18 | BIT17 | BIT16 | BIT9 | BIT8, 0x101); /* 5'b00101); */ ++ else if (82 <= channelToSW && channelToSW <= 140) + phy_set_rf_reg(pAdapter, eRFPath, RF_CHNLBW_Jaguar, BIT18 | BIT17 | BIT16 | BIT9 | BIT8, 0x301); /* 5'b01101); */ + else if (140 < channelToSW) + phy_set_rf_reg(pAdapter, eRFPath, RF_CHNLBW_Jaguar, BIT18 | BIT17 | BIT16 | BIT9 | BIT8, 0x501); /* 5'b10101); */ @@ -339244,25 +335922,25 @@ index 000000000..4fb1b8cef + /* <20130104, Kordan> APK for MP chip is done on initialization from folder. */ + if (IS_HARDWARE_TYPE_8821U(pAdapter) && (!IS_NORMAL_CHIP(pHalData->version_id)) && channelToSW > 14) { + /* <20121116, Kordan> For better result of APK. Asked by AlexWang. */ -+ if (36 <= channelToSW && channelToSW <= 64) ++ if (15 <= channelToSW && channelToSW <= 80) + phy_set_rf_reg(pAdapter, eRFPath, RF_APK_Jaguar, bRFRegOffsetMask, 0x710E7); -+ else if (100 <= channelToSW && channelToSW <= 140) ++ else if (82 <= channelToSW && channelToSW <= 140) + phy_set_rf_reg(pAdapter, eRFPath, RF_APK_Jaguar, bRFRegOffsetMask, 0x716E9); + else + phy_set_rf_reg(pAdapter, eRFPath, RF_APK_Jaguar, bRFRegOffsetMask, 0x714E9); + } else if (IS_HARDWARE_TYPE_8821S(pAdapter) && channelToSW > 14) { + /* <20130111, Kordan> For better result of APK. Asked by Willson. */ -+ if (36 <= channelToSW && channelToSW <= 64) ++ if (15 <= channelToSW && channelToSW <= 80) + phy_set_rf_reg(pAdapter, eRFPath, RF_APK_Jaguar, bRFRegOffsetMask, 0x714E9); -+ else if (100 <= channelToSW && channelToSW <= 140) ++ else if (82 <= channelToSW && channelToSW <= 140) + phy_set_rf_reg(pAdapter, eRFPath, RF_APK_Jaguar, bRFRegOffsetMask, 0x110E9); + else + phy_set_rf_reg(pAdapter, eRFPath, RF_APK_Jaguar, bRFRegOffsetMask, 0x714E9); + } else if (IS_HARDWARE_TYPE_8821E(pAdapter) && channelToSW > 14) { + /* <20130613, Kordan> For better result of APK. Asked by Willson. */ -+ if (36 <= channelToSW && channelToSW <= 64) ++ if (15 <= channelToSW && channelToSW <= 80) + phy_set_rf_reg(pAdapter, eRFPath, RF_APK_Jaguar, bRFRegOffsetMask, 0x114E9); -+ else if (100 <= channelToSW && channelToSW <= 140) ++ else if (82 <= channelToSW && channelToSW <= 140) + phy_set_rf_reg(pAdapter, eRFPath, RF_APK_Jaguar, bRFRegOffsetMask, 0x110E9); + else + phy_set_rf_reg(pAdapter, eRFPath, RF_APK_Jaguar, bRFRegOffsetMask, 0x110E9); @@ -339457,11 +336135,9 @@ index 000000000..4fb1b8cef + + /* RTW_INFO("<==%s()\n",__FUNCTION__); */ +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_rf6052.c linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_rf6052.c -new file mode 100644 -index 000000000..c2060b7b1 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_rf6052.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_rf6052.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_rf6052.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_rf6052.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_rf6052.c 2021-03-07 18:16:17.080957282 +0200 @@ -0,0 +1,158 @@ +/****************************************************************************** + * @@ -339621,11 +336297,9 @@ index 000000000..c2060b7b1 + + +/* End of HalRf6052.c */ -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_rxdesc.c linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_rxdesc.c -new file mode 100644 -index 000000000..1ae5f21fb ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_rxdesc.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_rxdesc.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_rxdesc.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_rxdesc.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_rxdesc.c 2021-03-07 18:16:17.080957282 +0200 @@ -0,0 +1,62 @@ +/****************************************************************************** + * @@ -339689,11 +336363,9 @@ index 000000000..1ae5f21fb + /* Offset 20 */ + /* pattrib->tsfl=(u8)GET_RX_STATUS_DESC_TSFL_8812(pdesc); */ +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_sreset.c linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_sreset.c -new file mode 100644 -index 000000000..43edc9728 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_sreset.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_sreset.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_sreset.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_sreset.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_sreset.c 2021-03-07 18:16:17.080957282 +0200 @@ -0,0 +1,106 @@ +/****************************************************************************** + * @@ -339801,11 +336473,9 @@ index 000000000..43edc9728 + } +} +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_xmit.c linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_xmit.c -new file mode 100644 -index 000000000..dd2887594 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_xmit.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_xmit.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_xmit.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_xmit.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_xmit.c 2021-03-07 18:16:17.080957282 +0200 @@ -0,0 +1,515 @@ +/****************************************************************************** + * @@ -340322,11 +336992,9 @@ index 000000000..dd2887594 + + return SCSettingOfDesc; +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/usb/rtl8812au_led.c linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/usb/rtl8812au_led.c -new file mode 100644 -index 000000000..e9ed78a23 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/usb/rtl8812au_led.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/usb/rtl8812au_led.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/usb/rtl8812au_led.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/usb/rtl8812au_led.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/usb/rtl8812au_led.c 2021-03-07 18:16:17.080957282 +0200 @@ -0,0 +1,389 @@ +/****************************************************************************** + * @@ -340717,11 +337385,9 @@ index 000000000..e9ed78a23 + DeInitLed(&(ledpriv->SwLed2)); +} +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/usb/rtl8812au_recv.c linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/usb/rtl8812au_recv.c -new file mode 100644 -index 000000000..5f0f621fe ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/usb/rtl8812au_recv.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/usb/rtl8812au_recv.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/usb/rtl8812au_recv.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/usb/rtl8812au_recv.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/usb/rtl8812au_recv.c 2021-03-07 18:16:17.080957282 +0200 @@ -0,0 +1,28 @@ +/****************************************************************************** + * @@ -340751,11 +337417,9 @@ index 000000000..5f0f621fe +{ + usb_free_recv_priv(padapter, INTERRUPT_MSG_FORMAT_LEN); +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/usb/rtl8812au_xmit.c linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/usb/rtl8812au_xmit.c -new file mode 100644 -index 000000000..8da4f79ce ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/usb/rtl8812au_xmit.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/usb/rtl8812au_xmit.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/usb/rtl8812au_xmit.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/usb/rtl8812au_xmit.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/usb/rtl8812au_xmit.c 2021-03-07 18:16:17.080957282 +0200 @@ -0,0 +1,1169 @@ +/****************************************************************************** + * @@ -341926,11 +338590,9 @@ index 000000000..8da4f79ce + +} +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/usb/usb_halinit.c linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/usb/usb_halinit.c -new file mode 100644 -index 000000000..37d6cec0a ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/usb/usb_halinit.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/usb/usb_halinit.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/usb/usb_halinit.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/usb/usb_halinit.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/usb/usb_halinit.c 2021-03-07 18:16:17.080957282 +0200 @@ -0,0 +1,2716 @@ +/****************************************************************************** + * @@ -344648,11 +341310,9 @@ index 000000000..37d6cec0a + rtl8812_set_hal_ops(pHalFunc); + +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/usb/usb_ops_linux.c linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/usb/usb_ops_linux.c -new file mode 100644 -index 000000000..22f8c42cf ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8812a/usb/usb_ops_linux.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/usb/usb_ops_linux.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/usb/usb_ops_linux.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/usb/usb_ops_linux.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8812a/usb/usb_ops_linux.c 2021-03-07 18:16:17.081957329 +0200 @@ -0,0 +1,244 @@ +/****************************************************************************** + * @@ -344898,115 +341558,9 @@ index 000000000..22f8c42cf + RTW_INFO("CHIP TYPE: RTL8811AU or RTL8821U\n"); + } +} -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/Hal8814PwrSeq.c linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/Hal8814PwrSeq.c -new file mode 100644 -index 000000000..c11a36e96 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/Hal8814PwrSeq.c -@@ -0,0 +1,98 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA -+ * -+ * -+ ******************************************************************************/ -+ -+#include "Hal8814PwrSeq.h" -+#include -+ -+/* -+ drivers should parse below arrays and do the corresponding actions -+*/ -+//3 Power on Array -+WLAN_PWR_CFG rtl8814A_power_on_flow[RTL8814A_TRANS_CARDEMU_TO_ACT_STEPS+RTL8814A_TRANS_END_STEPS]= -+{ -+ RTL8814A_TRANS_CARDEMU_TO_ACT -+ RTL8814A_TRANS_END -+}; -+ -+//3Radio off GPIO Array -+WLAN_PWR_CFG rtl8814A_radio_off_flow[RTL8814A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8814A_TRANS_END_STEPS]= -+{ -+ RTL8814A_TRANS_ACT_TO_CARDEMU -+ RTL8814A_TRANS_END -+}; -+ -+//3Card Disable Array -+WLAN_PWR_CFG rtl8814A_card_disable_flow[RTL8814A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8814A_TRANS_CARDEMU_TO_PDN_STEPS+RTL8814A_TRANS_END_STEPS]= -+{ -+ RTL8814A_TRANS_ACT_TO_CARDEMU -+ RTL8814A_TRANS_CARDEMU_TO_CARDDIS -+ RTL8814A_TRANS_END -+}; -+ -+//3 Card Enable Array -+WLAN_PWR_CFG rtl8814A_card_enable_flow[RTL8814A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8814A_TRANS_CARDEMU_TO_PDN_STEPS+RTL8814A_TRANS_END_STEPS]= -+{ -+ RTL8814A_TRANS_CARDDIS_TO_CARDEMU -+ RTL8814A_TRANS_CARDEMU_TO_ACT -+ RTL8814A_TRANS_END -+}; -+ -+//3Suspend Array -+WLAN_PWR_CFG rtl8814A_suspend_flow[RTL8814A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8814A_TRANS_CARDEMU_TO_SUS_STEPS+RTL8814A_TRANS_END_STEPS]= -+{ -+ RTL8814A_TRANS_ACT_TO_CARDEMU -+ RTL8814A_TRANS_CARDEMU_TO_SUS -+ RTL8814A_TRANS_END -+}; -+ -+//3 Resume Array -+WLAN_PWR_CFG rtl8814A_resume_flow[RTL8814A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8814A_TRANS_CARDEMU_TO_SUS_STEPS+RTL8814A_TRANS_END_STEPS]= -+{ -+ RTL8814A_TRANS_SUS_TO_CARDEMU -+ RTL8814A_TRANS_CARDEMU_TO_ACT -+ RTL8814A_TRANS_END -+}; -+ -+ -+ -+//3HWPDN Array -+WLAN_PWR_CFG rtl8814A_hwpdn_flow[RTL8814A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8814A_TRANS_CARDEMU_TO_PDN_STEPS+RTL8814A_TRANS_END_STEPS]= -+{ -+ RTL8814A_TRANS_ACT_TO_CARDEMU -+ RTL8814A_TRANS_CARDEMU_TO_PDN -+ RTL8814A_TRANS_END -+}; -+ -+//3 Enter LPS -+WLAN_PWR_CFG rtl8814A_enter_lps_flow[RTL8814A_TRANS_ACT_TO_LPS_STEPS+RTL8814A_TRANS_END_STEPS]= -+{ -+ //FW behavior -+ RTL8814A_TRANS_ACT_TO_LPS -+ RTL8814A_TRANS_END -+}; -+ -+//3 Leave LPS -+WLAN_PWR_CFG rtl8814A_leave_lps_flow[RTL8814A_TRANS_LPS_TO_ACT_STEPS+RTL8814A_TRANS_END_STEPS]= -+{ -+ //FW behavior -+ RTL8814A_TRANS_LPS_TO_ACT -+ RTL8814A_TRANS_END -+}; -+ -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/hal8814a_fw.c linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/hal8814a_fw.c -new file mode 100644 -index 000000000..fb01dd8c5 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/hal8814a_fw.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/hal8814a_fw.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8814a/hal8814a_fw.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/hal8814a_fw.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8814a/hal8814a_fw.c 2021-03-07 18:16:17.082957376 +0200 @@ -0,0 +1,7741 @@ +/****************************************************************************** +* @@ -352749,11 +349303,111 @@ index 000000000..fb01dd8c5 + +#endif // end of HWIMG_SUPPORT + -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_cmd.c linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_cmd.c -new file mode 100644 -index 000000000..6aa1fda17 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_cmd.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/Hal8814PwrSeq.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8814a/Hal8814PwrSeq.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/Hal8814PwrSeq.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8814a/Hal8814PwrSeq.c 2021-03-07 18:16:17.081957329 +0200 +@@ -0,0 +1,98 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++#include "Hal8814PwrSeq.h" ++#include ++ ++/* ++ drivers should parse below arrays and do the corresponding actions ++*/ ++//3 Power on Array ++WLAN_PWR_CFG rtl8814A_power_on_flow[RTL8814A_TRANS_CARDEMU_TO_ACT_STEPS+RTL8814A_TRANS_END_STEPS]= ++{ ++ RTL8814A_TRANS_CARDEMU_TO_ACT ++ RTL8814A_TRANS_END ++}; ++ ++//3Radio off GPIO Array ++WLAN_PWR_CFG rtl8814A_radio_off_flow[RTL8814A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8814A_TRANS_END_STEPS]= ++{ ++ RTL8814A_TRANS_ACT_TO_CARDEMU ++ RTL8814A_TRANS_END ++}; ++ ++//3Card Disable Array ++WLAN_PWR_CFG rtl8814A_card_disable_flow[RTL8814A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8814A_TRANS_CARDEMU_TO_PDN_STEPS+RTL8814A_TRANS_END_STEPS]= ++{ ++ RTL8814A_TRANS_ACT_TO_CARDEMU ++ RTL8814A_TRANS_CARDEMU_TO_CARDDIS ++ RTL8814A_TRANS_END ++}; ++ ++//3 Card Enable Array ++WLAN_PWR_CFG rtl8814A_card_enable_flow[RTL8814A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8814A_TRANS_CARDEMU_TO_PDN_STEPS+RTL8814A_TRANS_END_STEPS]= ++{ ++ RTL8814A_TRANS_CARDDIS_TO_CARDEMU ++ RTL8814A_TRANS_CARDEMU_TO_ACT ++ RTL8814A_TRANS_END ++}; ++ ++//3Suspend Array ++WLAN_PWR_CFG rtl8814A_suspend_flow[RTL8814A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8814A_TRANS_CARDEMU_TO_SUS_STEPS+RTL8814A_TRANS_END_STEPS]= ++{ ++ RTL8814A_TRANS_ACT_TO_CARDEMU ++ RTL8814A_TRANS_CARDEMU_TO_SUS ++ RTL8814A_TRANS_END ++}; ++ ++//3 Resume Array ++WLAN_PWR_CFG rtl8814A_resume_flow[RTL8814A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8814A_TRANS_CARDEMU_TO_SUS_STEPS+RTL8814A_TRANS_END_STEPS]= ++{ ++ RTL8814A_TRANS_SUS_TO_CARDEMU ++ RTL8814A_TRANS_CARDEMU_TO_ACT ++ RTL8814A_TRANS_END ++}; ++ ++ ++ ++//3HWPDN Array ++WLAN_PWR_CFG rtl8814A_hwpdn_flow[RTL8814A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8814A_TRANS_CARDEMU_TO_PDN_STEPS+RTL8814A_TRANS_END_STEPS]= ++{ ++ RTL8814A_TRANS_ACT_TO_CARDEMU ++ RTL8814A_TRANS_CARDEMU_TO_PDN ++ RTL8814A_TRANS_END ++}; ++ ++//3 Enter LPS ++WLAN_PWR_CFG rtl8814A_enter_lps_flow[RTL8814A_TRANS_ACT_TO_LPS_STEPS+RTL8814A_TRANS_END_STEPS]= ++{ ++ //FW behavior ++ RTL8814A_TRANS_ACT_TO_LPS ++ RTL8814A_TRANS_END ++}; ++ ++//3 Leave LPS ++WLAN_PWR_CFG rtl8814A_leave_lps_flow[RTL8814A_TRANS_LPS_TO_ACT_STEPS+RTL8814A_TRANS_END_STEPS]= ++{ ++ //FW behavior ++ RTL8814A_TRANS_LPS_TO_ACT ++ RTL8814A_TRANS_END ++}; ++ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_cmd.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_cmd.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_cmd.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_cmd.c 2021-03-07 18:16:17.082957376 +0200 @@ -0,0 +1,1515 @@ +/****************************************************************************** + * @@ -354270,11 +350924,9 @@ index 000000000..6aa1fda17 + +#endif // CONFIG_BT_COEXIST + -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_dm.c linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_dm.c -new file mode 100644 -index 000000000..10d7c7825 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_dm.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_dm.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_dm.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_dm.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_dm.c 2021-03-07 18:16:17.082957376 +0200 @@ -0,0 +1,407 @@ +/****************************************************************************** + * @@ -354683,11 +351335,9 @@ index 000000000..10d7c7825 +} +#endif //CONFIG_ANTENNA_DIVERSITY + -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_hal_init.c linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_hal_init.c -new file mode 100644 -index 000000000..b93ed3174 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_hal_init.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_hal_init.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_hal_init.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_hal_init.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_hal_init.c 2021-03-07 18:16:17.083957423 +0200 @@ -0,0 +1,6769 @@ +/****************************************************************************** + * @@ -361458,11 +358108,9 @@ index 000000000..b93ed3174 +} + + -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_phycfg.c linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_phycfg.c -new file mode 100644 -index 000000000..1c212540c ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_phycfg.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_phycfg.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_phycfg.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_phycfg.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_phycfg.c 2021-03-07 18:16:17.083957423 +0200 @@ -0,0 +1,3027 @@ +/****************************************************************************** + * @@ -364491,11 +361139,9 @@ index 000000000..1c212540c + //RTW_INFO("<==%s()\n",__FUNCTION__); +} + -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_rf6052.c linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_rf6052.c -new file mode 100644 -index 000000000..f298471ad ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_rf6052.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_rf6052.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_rf6052.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_rf6052.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_rf6052.c 2021-03-07 18:16:17.083957423 +0200 @@ -0,0 +1,210 @@ +/****************************************************************************** + * @@ -364707,11 +361353,9 @@ index 000000000..f298471ad + +/* End of HalRf6052.c */ + -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_rxdesc.c linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_rxdesc.c -new file mode 100644 -index 000000000..7de802c6c ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_rxdesc.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_rxdesc.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_rxdesc.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_rxdesc.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_rxdesc.c 2021-03-07 18:16:17.083957423 +0200 @@ -0,0 +1,68 @@ +/****************************************************************************** + * @@ -364781,11 +361425,9 @@ index 000000000..7de802c6c + +} + -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_sreset.c linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_sreset.c -new file mode 100644 -index 000000000..5d7e423ce ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_sreset.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_sreset.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_sreset.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_sreset.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_sreset.c 2021-03-07 18:16:17.083957423 +0200 @@ -0,0 +1,114 @@ +/****************************************************************************** + * @@ -364901,11 +361543,9 @@ index 000000000..5d7e423ce +} +#endif + -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_xmit.c linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_xmit.c -new file mode 100644 -index 000000000..8e9047b82 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_xmit.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_xmit.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_xmit.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_xmit.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_xmit.c 2021-03-07 18:16:17.083957423 +0200 @@ -0,0 +1,515 @@ +/****************************************************************************** + * @@ -365422,11 +362062,9 @@ index 000000000..8e9047b82 +} + + -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/usb/rtl8814au_led.c linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/usb/rtl8814au_led.c -new file mode 100644 -index 000000000..070f886e6 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/usb/rtl8814au_led.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/usb/rtl8814au_led.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8814a/usb/rtl8814au_led.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/usb/rtl8814au_led.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8814a/usb/rtl8814au_led.c 2021-03-07 18:16:17.083957423 +0200 @@ -0,0 +1,147 @@ +/****************************************************************************** + * @@ -365575,11 +362213,9 @@ index 000000000..070f886e6 + DeInitLed( &(ledpriv->SwLed2) ); +} +#endif -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/usb/rtl8814au_recv.c linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/usb/rtl8814au_recv.c -new file mode 100644 -index 000000000..4d381791b ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/usb/rtl8814au_recv.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/usb/rtl8814au_recv.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8814a/usb/rtl8814au_recv.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/usb/rtl8814au_recv.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8814a/usb/rtl8814au_recv.c 2021-03-07 18:16:17.083957423 +0200 @@ -0,0 +1,34 @@ +/****************************************************************************** + * @@ -365615,11 +362251,9 @@ index 000000000..4d381791b + usb_free_recv_priv(padapter, INTERRUPT_MSG_FORMAT_LEN); +} + -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/usb/rtl8814au_xmit.c linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/usb/rtl8814au_xmit.c -new file mode 100644 -index 000000000..482040b57 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/usb/rtl8814au_xmit.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/usb/rtl8814au_xmit.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8814a/usb/rtl8814au_xmit.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/usb/rtl8814au_xmit.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8814a/usb/rtl8814au_xmit.c 2021-03-07 18:16:17.083957423 +0200 @@ -0,0 +1,1129 @@ +/****************************************************************************** + * @@ -366750,11 +363384,9 @@ index 000000000..482040b57 +} +#endif + -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/usb/usb_halinit.c linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/usb/usb_halinit.c -new file mode 100644 -index 000000000..5c0bf0d03 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/usb/usb_halinit.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/usb/usb_halinit.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8814a/usb/usb_halinit.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/usb/usb_halinit.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8814a/usb/usb_halinit.c 2021-03-07 18:16:17.083957423 +0200 @@ -0,0 +1,2416 @@ +/****************************************************************************** + * @@ -369172,11 +365804,9 @@ index 000000000..5c0bf0d03 + +} + -diff --git linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/usb/usb_ops_linux.c linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/usb/usb_ops_linux.c -new file mode 100644 -index 000000000..320024cae ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/hal/rtl8814a/usb/usb_ops_linux.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/usb/usb_ops_linux.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8814a/usb/usb_ops_linux.c +--- linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/usb/usb_ops_linux.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/hal/rtl8814a/usb/usb_ops_linux.c 2021-03-07 18:16:17.083957423 +0200 @@ -0,0 +1,312 @@ +/****************************************************************************** + * @@ -369490,3040 +366120,9 @@ index 000000000..320024cae + pdvobj->HardwareType = HARDWARE_TYPE_RTL8814AU; + RTW_INFO("CHIP TYPE: RTL8814\n"); +} -diff --git linux-5.8/3rdparty/rtl8812au/include/Hal8812PhyCfg.h linux-5.8/3rdparty/rtl8812au/include/Hal8812PhyCfg.h -new file mode 100644 -index 000000000..0d5282a42 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/Hal8812PhyCfg.h -@@ -0,0 +1,143 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+#ifndef __INC_HAL8812PHYCFG_H__ -+#define __INC_HAL8812PHYCFG_H__ -+ -+ -+/*--------------------------Define Parameters-------------------------------*/ -+#define LOOP_LIMIT 5 -+#define MAX_STALL_TIME 50 /* us */ -+#define AntennaDiversityValue 0x80 /* (Adapter->bSoftwareAntennaDiversity ? 0x00 : 0x80) */ -+#define MAX_TXPWR_IDX_NMODE_92S 63 -+#define Reset_Cnt_Limit 3 -+ -+ -+#ifdef CONFIG_PCI_HCI -+ #define MAX_AGGR_NUM 0x0B -+#else -+ #define MAX_AGGR_NUM 0x07 -+#endif /* CONFIG_PCI_HCI */ -+ -+ -+/*--------------------------Define Parameters-------------------------------*/ -+ -+/*------------------------------Define structure----------------------------*/ -+ -+ -+/* BB/RF related */ -+ -+/*------------------------------Define structure----------------------------*/ -+ -+ -+/*------------------------Export global variable----------------------------*/ -+/*------------------------Export global variable----------------------------*/ -+ -+ -+/*------------------------Export Marco Definition---------------------------*/ -+/*------------------------Export Marco Definition---------------------------*/ -+ -+ -+/*--------------------------Exported Function prototype---------------------*/ -+/* -+ * BB and RF register read/write -+ * */ -+u32 PHY_QueryBBReg8812(IN PADAPTER Adapter, -+ IN u32 RegAddr, -+ IN u32 BitMask); -+void PHY_SetBBReg8812(IN PADAPTER Adapter, -+ IN u32 RegAddr, -+ IN u32 BitMask, -+ IN u32 Data); -+u32 PHY_QueryRFReg8812(IN PADAPTER Adapter, -+ IN enum rf_path eRFPath, -+ IN u32 RegAddr, -+ IN u32 BitMask); -+void PHY_SetRFReg8812(IN PADAPTER Adapter, -+ IN enum rf_path eRFPath, -+ IN u32 RegAddr, -+ IN u32 BitMask, -+ IN u32 Data); -+ -+/* -+ * Initialization related function -+ * -+ * MAC/BB/RF HAL config */ -+int PHY_MACConfig8812(IN PADAPTER Adapter); -+int PHY_BBConfig8812(IN PADAPTER Adapter); -+void PHY_BB8812_Config_1T(IN PADAPTER Adapter); -+int PHY_RFConfig8812(IN PADAPTER Adapter); -+ -+/* RF config */ -+ -+s32 -+PHY_SwitchWirelessBand8812( -+ IN PADAPTER Adapter, -+ IN u8 Band -+); -+ -+/* -+ * BB TX Power R/W -+ * */ -+void PHY_GetTxPowerLevel8812(IN PADAPTER Adapter, OUT s32 *powerlevel); -+void PHY_SetTxPowerLevel8812(IN PADAPTER Adapter, IN u8 Channel); -+ -+BOOLEAN PHY_UpdateTxPowerDbm8812(IN PADAPTER Adapter, IN int powerInDbm); -+u8 PHY_GetTxPowerIndex_8812A( -+ IN PADAPTER pAdapter, -+ IN enum rf_path RFPath, -+ IN u8 Rate, -+ IN u8 BandWidth, -+ IN u8 Channel, -+ struct txpwr_idx_comp *tic -+); -+ -+u32 phy_get_tx_bb_swing_8812a( -+ IN PADAPTER Adapter, -+ IN BAND_TYPE Band, -+ IN enum rf_path RFPath -+); -+ -+VOID -+PHY_SetTxPowerIndex_8812A( -+ IN PADAPTER Adapter, -+ IN u32 PowerIndex, -+ IN enum rf_path RFPath, -+ IN u8 Rate -+); -+ -+/* -+ * channel switch related funciton -+ * */ -+VOID -+PHY_SetSwChnlBWMode8812( -+ IN PADAPTER Adapter, -+ IN u8 channel, -+ IN enum channel_width Bandwidth, -+ IN u8 Offset40, -+ IN u8 Offset80 -+); -+ -+/* -+ * BB/MAC/RF other monitor API -+ * */ -+ -+VOID -+phy_set_rf_path_switch_8812a( -+ IN struct dm_struct *phydm, -+ IN bool bMain -+); -+ -+/*--------------------------Exported Function prototype---------------------*/ -+#endif /* __INC_HAL8192CPHYCFG_H */ -diff --git linux-5.8/3rdparty/rtl8812au/include/Hal8812PhyReg.h linux-5.8/3rdparty/rtl8812au/include/Hal8812PhyReg.h -new file mode 100644 -index 000000000..521ebb202 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/Hal8812PhyReg.h -@@ -0,0 +1,735 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+#ifndef __INC_HAL8812PHYREG_H__ -+#define __INC_HAL8812PHYREG_H__ -+/*--------------------------Define Parameters-------------------------------*/ -+/* -+ * BB-PHY register PMAC 0x100 PHY 0x800 - 0xEFF -+ * 1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF -+ * 2. 0x800/0x900/0xA00/0xC00/0xD00/0xE00 -+ * 3. RF register 0x00-2E -+ * 4. Bit Mask for BB/RF register -+ * 5. Other defintion for BB/RF R/W -+ * */ -+ -+ -+/* BB Register Definition */ -+ -+#define rCCAonSec_Jaguar 0x838 -+#define rPwed_TH_Jaguar 0x830 -+ -+/* BW and sideband setting */ -+#define rBWIndication_Jaguar 0x834 -+#define rL1PeakTH_Jaguar 0x848 -+#define rFPGA0_XA_LSSIReadBack 0x8a0 /*Tranceiver LSSI Readback*/ -+#define rRFMOD_Jaguar 0x8ac /* RF mode */ -+#define rADC_Buf_Clk_Jaguar 0x8c4 -+#define rRFECTRL_Jaguar 0x900 -+#define bRFMOD_Jaguar 0xc3 -+#define rCCK_System_Jaguar 0xa00 /* for cck sideband */ -+#define bCCK_System_Jaguar 0x10 -+ -+/* Block & Path enable */ -+#define rOFDMCCKEN_Jaguar 0x808 /* OFDM/CCK block enable */ -+#define bOFDMEN_Jaguar 0x20000000 -+#define bCCKEN_Jaguar 0x10000000 -+#define rRxPath_Jaguar 0x808 /* Rx antenna */ -+#define bRxPath_Jaguar 0xff -+#define rTxPath_Jaguar 0x80c /* Tx antenna */ -+#define bTxPath_Jaguar 0x0fffffff -+#define rCCK_RX_Jaguar 0xa04 /* for cck rx path selection */ -+#define bCCK_RX_Jaguar 0x0c000000 -+#define rVhtlen_Use_Lsig_Jaguar 0x8c3 /* Use LSIG for VHT length */ -+ -+/* RF read/write-related */ -+#define rHSSIRead_Jaguar 0x8b0 /* RF read addr */ -+#define bHSSIRead_addr_Jaguar 0xff -+#define bHSSIRead_trigger_Jaguar 0x100 -+#define rA_PIRead_Jaguar 0xd04 /* RF readback with PI */ -+#define rB_PIRead_Jaguar 0xd44 /* RF readback with PI */ -+#define rA_SIRead_Jaguar 0xd08 /* RF readback with SI */ -+#define rB_SIRead_Jaguar 0xd48 /* RF readback with SI */ -+#define rRead_data_Jaguar 0xfffff -+#define rA_LSSIWrite_Jaguar 0xc90 /* RF write addr */ -+#define rB_LSSIWrite_Jaguar 0xe90 /* RF write addr */ -+#define bLSSIWrite_data_Jaguar 0x000fffff -+#define bLSSIWrite_addr_Jaguar 0x0ff00000 -+ -+ -+ -+/* YN: mask the following register definition temporarily */ -+#define rFPGA0_XA_RFInterfaceOE 0x860 /* RF Channel switch */ -+#define rFPGA0_XB_RFInterfaceOE 0x864 -+ -+#define rFPGA0_XAB_RFInterfaceSW 0x870 /* RF Interface Software Control */ -+#define rFPGA0_XCD_RFInterfaceSW 0x874 -+ -+/* #define rFPGA0_XAB_RFParameter 0x878 */ /* RF Parameter -+ * #define rFPGA0_XCD_RFParameter 0x87c */ -+ -+/* #define rFPGA0_AnalogParameter1 0x880 */ /* Crystal cap setting RF-R/W protection for parameter4?? -+ * #define rFPGA0_AnalogParameter2 0x884 -+ * #define rFPGA0_AnalogParameter3 0x888 -+ * #define rFPGA0_AdDaClockEn 0x888 */ /* enable ad/da clock1 for dual-phy -+ * #define rFPGA0_AnalogParameter4 0x88c */ -+ -+ -+/* CCK TX scaling */ -+#define rCCK_TxFilter1_Jaguar 0xa20 -+#define bCCK_TxFilter1_C0_Jaguar 0x00ff0000 -+#define bCCK_TxFilter1_C1_Jaguar 0xff000000 -+#define rCCK_TxFilter2_Jaguar 0xa24 -+#define bCCK_TxFilter2_C2_Jaguar 0x000000ff -+#define bCCK_TxFilter2_C3_Jaguar 0x0000ff00 -+#define bCCK_TxFilter2_C4_Jaguar 0x00ff0000 -+#define bCCK_TxFilter2_C5_Jaguar 0xff000000 -+#define rCCK_TxFilter3_Jaguar 0xa28 -+#define bCCK_TxFilter3_C6_Jaguar 0x000000ff -+#define bCCK_TxFilter3_C7_Jaguar 0x0000ff00 -+ -+ -+/* YN: mask the following register definition temporarily -+ * #define rPdp_AntA 0xb00 -+ * #define rPdp_AntA_4 0xb04 -+ * #define rConfig_Pmpd_AntA 0xb28 -+ * #define rConfig_AntA 0xb68 -+ * #define rConfig_AntB 0xb6c -+ * #define rPdp_AntB 0xb70 -+ * #define rPdp_AntB_4 0xb74 -+ * #define rConfig_Pmpd_AntB 0xb98 -+ * #define rAPK 0xbd8 */ -+ -+/* RXIQC */ -+#define rA_RxIQC_AB_Jaguar 0xc10 /* RxIQ imblance matrix coeff. A & B */ -+#define rA_RxIQC_CD_Jaguar 0xc14 /* RxIQ imblance matrix coeff. C & D */ -+#define rA_TxScale_Jaguar 0xc1c /* Pah_A TX scaling factor */ -+#define rB_TxScale_Jaguar 0xe1c /* Path_B TX scaling factor */ -+#define rB_RxIQC_AB_Jaguar 0xe10 /* RxIQ imblance matrix coeff. A & B */ -+#define rB_RxIQC_CD_Jaguar 0xe14 /* RxIQ imblance matrix coeff. C & D */ -+#define b_RxIQC_AC_Jaguar 0x02ff /* bit mask for IQC matrix element A & C */ -+#define b_RxIQC_BD_Jaguar 0x02ff0000 /* bit mask for IQC matrix element A & C */ -+ -+ -+/* DIG-related */ -+#define rA_IGI_Jaguar 0xc50 /* Initial Gain for path-A */ -+#define rB_IGI_Jaguar 0xe50 /* Initial Gain for path-B */ -+#define rOFDM_FalseAlarm1_Jaguar 0xf48 /* counter for break */ -+#define rOFDM_FalseAlarm2_Jaguar 0xf4c /* counter for spoofing */ -+#define rCCK_FalseAlarm_Jaguar 0xa5c /* counter for cck false alarm */ -+#define b_FalseAlarm_Jaguar 0xffff -+#define rCCK_CCA_Jaguar 0xa08 /* cca threshold */ -+#define bCCK_CCA_Jaguar 0x00ff0000 -+ -+/* Tx Power Ttraining-related */ -+#define rA_TxPwrTraing_Jaguar 0xc54 -+#define rB_TxPwrTraing_Jaguar 0xe54 -+ -+/* Report-related */ -+#define rOFDM_ShortCFOAB_Jaguar 0xf60 -+#define rOFDM_LongCFOAB_Jaguar 0xf64 -+#define rOFDM_EndCFOAB_Jaguar 0xf70 -+#define rOFDM_AGCReport_Jaguar 0xf84 -+#define rOFDM_RxSNR_Jaguar 0xf88 -+#define rOFDM_RxEVMCSI_Jaguar 0xf8c -+#define rOFDM_SIGReport_Jaguar 0xf90 -+ -+/* Misc functions */ -+#define rEDCCA_Jaguar 0x8a4 /* EDCCA */ -+#define bEDCCA_Jaguar 0xffff -+#define rAGC_table_Jaguar 0x82c /* AGC tabel select */ -+#define bAGC_table_Jaguar 0x3 -+#define b_sel5g_Jaguar 0x1000 /* sel5g */ -+#define b_LNA_sw_Jaguar 0x8000 /* HW/WS control for LNA */ -+#define rFc_area_Jaguar 0x860 /* fc_area */ -+#define bFc_area_Jaguar 0x1ffe000 -+#define rSingleTone_ContTx_Jaguar 0x914 -+ -+/* RFE */ -+#define rA_RFE_Pinmux_Jaguar 0xcb0 /* Path_A RFE cotrol pinmux */ -+#define rB_RFE_Pinmux_Jaguar 0xeb0 /* Path_B RFE control pinmux */ -+#define rA_RFE_Inv_Jaguar 0xcb4 /* Path_A RFE cotrol */ -+#define rB_RFE_Inv_Jaguar 0xeb4 /* Path_B RFE control */ -+#define rA_RFE_Jaguar 0xcb8 /* Path_A RFE cotrol */ -+#define rB_RFE_Jaguar 0xeb8 /* Path_B RFE control */ -+#define rA_RFE_Inverse_Jaguar 0xCBC /* Path_A RFE control inverse */ -+#define rB_RFE_Inverse_Jaguar 0xEBC /* Path_B RFE control inverse */ -+#define r_ANTSEL_SW_Jaguar 0x900 /* ANTSEL SW Control */ -+#define bMask_RFEInv_Jaguar 0x3ff00000 -+#define bMask_AntselPathFollow_Jaguar 0x00030000 -+ -+/* TX AGC */ -+#define rTxAGC_A_CCK11_CCK1_JAguar 0xc20 -+#define rTxAGC_A_Ofdm18_Ofdm6_JAguar 0xc24 -+#define rTxAGC_A_Ofdm54_Ofdm24_JAguar 0xc28 -+#define rTxAGC_A_MCS3_MCS0_JAguar 0xc2c -+#define rTxAGC_A_MCS7_MCS4_JAguar 0xc30 -+#define rTxAGC_A_MCS11_MCS8_JAguar 0xc34 -+#define rTxAGC_A_MCS15_MCS12_JAguar 0xc38 -+#define rTxAGC_A_Nss1Index3_Nss1Index0_JAguar 0xc3c -+#define rTxAGC_A_Nss1Index7_Nss1Index4_JAguar 0xc40 -+#define rTxAGC_A_Nss2Index1_Nss1Index8_JAguar 0xc44 -+#define rTxAGC_A_Nss2Index5_Nss2Index2_JAguar 0xc48 -+#define rTxAGC_A_Nss2Index9_Nss2Index6_JAguar 0xc4c -+#define rTxAGC_B_CCK11_CCK1_JAguar 0xe20 -+#define rTxAGC_B_Ofdm18_Ofdm6_JAguar 0xe24 -+#define rTxAGC_B_Ofdm54_Ofdm24_JAguar 0xe28 -+#define rTxAGC_B_MCS3_MCS0_JAguar 0xe2c -+#define rTxAGC_B_MCS7_MCS4_JAguar 0xe30 -+#define rTxAGC_B_MCS11_MCS8_JAguar 0xe34 -+#define rTxAGC_B_MCS15_MCS12_JAguar 0xe38 -+#define rTxAGC_B_Nss1Index3_Nss1Index0_JAguar 0xe3c -+#define rTxAGC_B_Nss1Index7_Nss1Index4_JAguar 0xe40 -+#define rTxAGC_B_Nss2Index1_Nss1Index8_JAguar 0xe44 -+#define rTxAGC_B_Nss2Index5_Nss2Index2_JAguar 0xe48 -+#define rTxAGC_B_Nss2Index9_Nss2Index6_JAguar 0xe4c -+#define bTxAGC_byte0_Jaguar 0xff -+#define bTxAGC_byte1_Jaguar 0xff00 -+#define bTxAGC_byte2_Jaguar 0xff0000 -+#define bTxAGC_byte3_Jaguar 0xff000000 -+ -+/* IQK YN: temporaily mask this part -+ * #define rFPGA0_IQK 0xe28 -+ * #define rTx_IQK_Tone_A 0xe30 -+ * #define rRx_IQK_Tone_A 0xe34 -+ * #define rTx_IQK_PI_A 0xe38 -+ * #define rRx_IQK_PI_A 0xe3c */ -+ -+/* #define rTx_IQK 0xe40 */ -+/* #define rRx_IQK 0xe44 */ -+/* #define rIQK_AGC_Pts 0xe48 */ -+/* #define rIQK_AGC_Rsp 0xe4c */ -+/* #define rTx_IQK_Tone_B 0xe50 */ -+/* #define rRx_IQK_Tone_B 0xe54 */ -+/* #define rTx_IQK_PI_B 0xe58 */ -+/* #define rRx_IQK_PI_B 0xe5c */ -+/* #define rIQK_AGC_Cont 0xe60 */ -+ -+ -+/* AFE-related */ -+#define rA_AFEPwr1_Jaguar 0xc60 /* dynamic AFE power control */ -+#define rA_AFEPwr2_Jaguar 0xc64 /* dynamic AFE power control */ -+#define rA_Rx_WaitCCA_Tx_CCKRFON_Jaguar 0xc68 -+#define rA_Tx_CCKBBON_OFDMRFON_Jaguar 0xc6c -+#define rA_Tx_OFDMBBON_Tx2Rx_Jaguar 0xc70 -+#define rA_Tx2Tx_RXCCK_Jaguar 0xc74 -+#define rA_Rx_OFDM_WaitRIFS_Jaguar 0xc78 -+#define rA_Rx2Rx_BT_Jaguar 0xc7c -+#define rA_sleep_nav_Jaguar 0xc80 -+#define rA_pmpd_Jaguar 0xc84 -+#define rB_AFEPwr1_Jaguar 0xe60 /* dynamic AFE power control */ -+#define rB_AFEPwr2_Jaguar 0xe64 /* dynamic AFE power control */ -+#define rB_Rx_WaitCCA_Tx_CCKRFON_Jaguar 0xe68 -+#define rB_Tx_CCKBBON_OFDMRFON_Jaguar 0xe6c -+#define rB_Tx_OFDMBBON_Tx2Rx_Jaguar 0xe70 -+#define rB_Tx2Tx_RXCCK_Jaguar 0xe74 -+#define rB_Rx_OFDM_WaitRIFS_Jaguar 0xe78 -+#define rB_Rx2Rx_BT_Jaguar 0xe7c -+#define rB_sleep_nav_Jaguar 0xe80 -+#define rB_pmpd_Jaguar 0xe84 -+ -+ -+/* YN: mask these registers temporaily -+ * #define rTx_Power_Before_IQK_A 0xe94 -+ * #define rTx_Power_After_IQK_A 0xe9c */ -+ -+/* #define rRx_Power_Before_IQK_A 0xea0 */ -+/* #define rRx_Power_Before_IQK_A_2 0xea4 */ -+/* #define rRx_Power_After_IQK_A 0xea8 */ -+/* #define rRx_Power_After_IQK_A_2 0xeac */ -+ -+/* #define rTx_Power_Before_IQK_B 0xeb4 */ -+/* #define rTx_Power_After_IQK_B 0xebc */ -+ -+/* #define rRx_Power_Before_IQK_B 0xec0 */ -+/* #define rRx_Power_Before_IQK_B_2 0xec4 */ -+/* #define rRx_Power_After_IQK_B 0xec8 */ -+/* #define rRx_Power_After_IQK_B_2 0xecc */ -+ -+ -+/* RSSI Dump */ -+#define rA_RSSIDump_Jaguar 0xBF0 -+#define rB_RSSIDump_Jaguar 0xBF1 -+#define rS1_RXevmDump_Jaguar 0xBF4 -+#define rS2_RXevmDump_Jaguar 0xBF5 -+#define rA_RXsnrDump_Jaguar 0xBF6 -+#define rB_RXsnrDump_Jaguar 0xBF7 -+#define rA_CfoShortDump_Jaguar 0xBF8 -+#define rB_CfoShortDump_Jaguar 0xBFA -+#define rA_CfoLongDump_Jaguar 0xBEC -+#define rB_CfoLongDump_Jaguar 0xBEE -+ -+ -+/* RF Register -+ * */ -+#define RF_AC_Jaguar 0x00 /* */ -+#define RF_RF_Top_Jaguar 0x07 /* */ -+#define RF_TXLOK_Jaguar 0x08 /* */ -+#define RF_TXAPK_Jaguar 0x0B -+#define RF_CHNLBW_Jaguar 0x18 /* RF channel and BW switch */ -+#define RF_RCK1_Jaguar 0x1c /* */ -+#define RF_RCK2_Jaguar 0x1d -+#define RF_RCK3_Jaguar 0x1e -+#define RF_ModeTableAddr 0x30 -+#define RF_ModeTableData0 0x31 -+#define RF_ModeTableData1 0x32 -+#define RF_TxLCTank_Jaguar 0x54 -+#define RF_APK_Jaguar 0x63 -+#define RF_LCK 0xB4 -+#define RF_WeLut_Jaguar 0xEF -+ -+#define bRF_CHNLBW_MOD_AG_Jaguar 0x70300 -+#define bRF_CHNLBW_BW 0xc00 -+ -+ -+/* -+ * RL6052 Register definition -+ * */ -+#define RF_AC 0x00 /* */ -+#define RF_IPA_A 0x0C /* */ -+#define RF_TXBIAS_A 0x0D -+#define RF_BS_PA_APSET_G9_G11 0x0E -+#define RF_MODE1 0x10 /* */ -+#define RF_MODE2 0x11 /* */ -+#define RF_CHNLBW 0x18 /* RF channel and BW switch */ -+#define RF_RCK_OS 0x30 /* RF TX PA control */ -+#define RF_TXPA_G1 0x31 /* RF TX PA control */ -+#define RF_TXPA_G2 0x32 /* RF TX PA control */ -+#define RF_TXPA_G3 0x33 /* RF TX PA control */ -+#define RF_0x52 0x52 -+#define RF_WE_LUT 0xEF -+ -+#define RF_TX_GAIN_OFFSET_8812A(_val) ((abs((_val)) << 1) | (((_val) > 0) ? BIT0 : 0)) -+#define RF_TX_GAIN_OFFSET_8821A(_val) ((abs((_val)) << 1) | (((_val) > 0) ? BIT0 : 0)) -+ -+/* -+ * Bit Mask -+ * -+ * 1. Page1(0x100) */ -+#define bBBResetB 0x100 /* Useless now? */ -+#define bGlobalResetB 0x200 -+#define bOFDMTxStart 0x4 -+#define bCCKTxStart 0x8 -+#define bCRC32Debug 0x100 -+#define bPMACLoopback 0x10 -+#define bTxLSIG 0xffffff -+#define bOFDMTxRate 0xf -+#define bOFDMTxReserved 0x10 -+#define bOFDMTxLength 0x1ffe0 -+#define bOFDMTxParity 0x20000 -+#define bTxHTSIG1 0xffffff -+#define bTxHTMCSRate 0x7f -+#define bTxHTBW 0x80 -+#define bTxHTLength 0xffff00 -+#define bTxHTSIG2 0xffffff -+#define bTxHTSmoothing 0x1 -+#define bTxHTSounding 0x2 -+#define bTxHTReserved 0x4 -+#define bTxHTAggreation 0x8 -+#define bTxHTSTBC 0x30 -+#define bTxHTAdvanceCoding 0x40 -+#define bTxHTShortGI 0x80 -+#define bTxHTNumberHT_LTF 0x300 -+#define bTxHTCRC8 0x3fc00 -+#define bCounterReset 0x10000 -+#define bNumOfOFDMTx 0xffff -+#define bNumOfCCKTx 0xffff0000 -+#define bTxIdleInterval 0xffff -+#define bOFDMService 0xffff0000 -+#define bTxMACHeader 0xffffffff -+#define bTxDataInit 0xff -+#define bTxHTMode 0x100 -+#define bTxDataType 0x30000 -+#define bTxRandomSeed 0xffffffff -+#define bCCKTxPreamble 0x1 -+#define bCCKTxSFD 0xffff0000 -+#define bCCKTxSIG 0xff -+#define bCCKTxService 0xff00 -+#define bCCKLengthExt 0x8000 -+#define bCCKTxLength 0xffff0000 -+#define bCCKTxCRC16 0xffff -+#define bCCKTxStatus 0x1 -+#define bOFDMTxStatus 0x2 -+ -+ -+/* -+ * 1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF -+ * 1. Page1(0x100) -+ * */ -+#define rPMAC_Reset 0x100 -+#define rPMAC_TxStart 0x104 -+#define rPMAC_TxLegacySIG 0x108 -+#define rPMAC_TxHTSIG1 0x10c -+#define rPMAC_TxHTSIG2 0x110 -+#define rPMAC_PHYDebug 0x114 -+#define rPMAC_TxPacketNum 0x118 -+#define rPMAC_TxIdle 0x11c -+#define rPMAC_TxMACHeader0 0x120 -+#define rPMAC_TxMACHeader1 0x124 -+#define rPMAC_TxMACHeader2 0x128 -+#define rPMAC_TxMACHeader3 0x12c -+#define rPMAC_TxMACHeader4 0x130 -+#define rPMAC_TxMACHeader5 0x134 -+#define rPMAC_TxDataType 0x138 -+#define rPMAC_TxRandomSeed 0x13c -+#define rPMAC_CCKPLCPPreamble 0x140 -+#define rPMAC_CCKPLCPHeader 0x144 -+#define rPMAC_CCKCRC16 0x148 -+#define rPMAC_OFDMRxCRC32OK 0x170 -+#define rPMAC_OFDMRxCRC32Er 0x174 -+#define rPMAC_OFDMRxParityEr 0x178 -+#define rPMAC_OFDMRxCRC8Er 0x17c -+#define rPMAC_CCKCRxRC16Er 0x180 -+#define rPMAC_CCKCRxRC32Er 0x184 -+#define rPMAC_CCKCRxRC32OK 0x188 -+#define rPMAC_TxStatus 0x18c -+ -+/* -+ * 3. Page8(0x800) -+ * */ -+#define rFPGA0_RFMOD 0x800 /* RF mode & CCK TxSC */ /* RF BW Setting?? */ -+ -+#define rFPGA0_TxInfo 0x804 /* Status report?? */ -+#define rFPGA0_PSDFunction 0x808 -+#define rFPGA0_TxGainStage 0x80c /* Set TX PWR init gain? */ -+ -+#define rFPGA0_XA_HSSIParameter1 0x820 /* RF 3 wire register */ -+#define rFPGA0_XA_HSSIParameter2 0x824 -+#define rFPGA0_XB_HSSIParameter1 0x828 -+#define rFPGA0_XB_HSSIParameter2 0x82c -+ -+#define rFPGA0_XAB_SwitchControl 0x858 /* RF Channel switch */ -+#define rFPGA0_XCD_SwitchControl 0x85c -+ -+#define rFPGA0_XAB_RFParameter 0x878 /* RF Parameter */ -+#define rFPGA0_XCD_RFParameter 0x87c -+ -+#define rFPGA0_AnalogParameter1 0x880 /* Crystal cap setting RF-R/W protection for parameter4?? */ -+#define rFPGA0_AnalogParameter2 0x884 -+#define rFPGA0_AnalogParameter3 0x888 -+#define rFPGA0_AdDaClockEn 0x888 /* enable ad/da clock1 for dual-phy */ -+#define rFPGA0_AnalogParameter4 0x88c -+#define rFPGA0_XB_LSSIReadBack 0x8a4 -+#define rFPGA0_XCD_RFPara 0x8b4 -+ -+/* -+ * 4. Page9(0x900) -+ * */ -+#define rFPGA1_RFMOD 0x900 /* RF mode & OFDM TxSC */ /* RF BW Setting?? */ -+ -+#define rFPGA1_TxBlock 0x904 /* Useless now */ -+#define rFPGA1_DebugSelect 0x908 /* Useless now */ -+#define rFPGA1_TxInfo 0x90c /* Useless now */ /* Status report?? */ -+ -+/* -+ * PageA(0xA00) -+ * */ -+#define rCCK0_System 0xa00 -+#define rCCK0_AFESetting 0xa04 /* Disable init gain now */ /* Select RX path by RSSI */ -+#define rCCK0_DSPParameter2 0xa1c /* SQ threshold */ -+#define rCCK0_TxFilter1 0xa20 -+#define rCCK0_TxFilter2 0xa24 -+#define rCCK0_DebugPort 0xa28 /* debug port and Tx filter3 */ -+#define rCCK0_FalseAlarmReport 0xa2c /* 0xa2d useless now 0xa30-a4f channel report */ -+ -+/* -+ * PageB(0xB00) -+ * */ -+#define rPdp_AntA 0xb00 -+#define rPdp_AntA_4 0xb04 -+#define rConfig_Pmpd_AntA 0xb28 -+#define rConfig_AntA 0xb68 -+#define rConfig_AntB 0xb6c -+#define rPdp_AntB 0xb70 -+#define rPdp_AntB_4 0xb74 -+#define rConfig_Pmpd_AntB 0xb98 -+#define rAPK 0xbd8 -+ -+/* -+ * 6. PageC(0xC00) -+ * */ -+#define rOFDM0_LSTF 0xc00 -+ -+#define rOFDM0_TRxPathEnable 0xc04 -+#define rOFDM0_TRMuxPar 0xc08 -+#define rOFDM0_TRSWIsolation 0xc0c -+ -+#define rOFDM0_XARxAFE 0xc10 /* RxIQ DC offset, Rx digital filter, DC notch filter */ -+#define rOFDM0_XARxIQImbalance 0xc14 /* RxIQ imblance matrix */ -+#define rOFDM0_XBRxAFE 0xc18 -+#define rOFDM0_XBRxIQImbalance 0xc1c -+#define rOFDM0_XCRxAFE 0xc20 -+#define rOFDM0_XCRxIQImbalance 0xc24 -+#define rOFDM0_XDRxAFE 0xc28 -+#define rOFDM0_XDRxIQImbalance 0xc2c -+ -+#define rOFDM0_RxDetector1 0xc30 /* PD, BW & SBD */ /* DM tune init gain */ -+#define rOFDM0_RxDetector2 0xc34 /* SBD & Fame Sync. */ -+#define rOFDM0_RxDetector3 0xc38 /* Frame Sync. */ -+#define rOFDM0_RxDetector4 0xc3c /* PD, SBD, Frame Sync & Short-GI */ -+ -+#define rOFDM0_RxDSP 0xc40 /* Rx Sync Path */ -+#define rOFDM0_CFOandDAGC 0xc44 /* CFO & DAGC */ -+#define rOFDM0_CCADropThreshold 0xc48 /* CCA Drop threshold */ -+#define rOFDM0_ECCAThreshold 0xc4c /* energy CCA */ -+ -+#define rOFDM0_XAAGCCore1 0xc50 /* DIG */ -+#define rOFDM0_XAAGCCore2 0xc54 -+#define rOFDM0_XBAGCCore1 0xc58 -+#define rOFDM0_XBAGCCore2 0xc5c -+#define rOFDM0_XCAGCCore1 0xc60 -+#define rOFDM0_XCAGCCore2 0xc64 -+#define rOFDM0_XDAGCCore1 0xc68 -+#define rOFDM0_XDAGCCore2 0xc6c -+ -+#define rOFDM0_AGCParameter1 0xc70 -+#define rOFDM0_AGCParameter2 0xc74 -+#define rOFDM0_AGCRSSITable 0xc78 -+#define rOFDM0_HTSTFAGC 0xc7c -+ -+#define rOFDM0_XATxIQImbalance 0xc80 /* TX PWR TRACK and DIG */ -+#define rOFDM0_XATxAFE 0xc84 -+#define rOFDM0_XBTxIQImbalance 0xc88 -+#define rOFDM0_XBTxAFE 0xc8c -+#define rOFDM0_XCTxIQImbalance 0xc90 -+#define rOFDM0_XCTxAFE 0xc94 -+#define rOFDM0_XDTxIQImbalance 0xc98 -+#define rOFDM0_XDTxAFE 0xc9c -+ -+#define rOFDM0_RxIQExtAnta 0xca0 -+#define rOFDM0_TxCoeff1 0xca4 -+#define rOFDM0_TxCoeff2 0xca8 -+#define rOFDM0_TxCoeff3 0xcac -+#define rOFDM0_TxCoeff4 0xcb0 -+#define rOFDM0_TxCoeff5 0xcb4 -+#define rOFDM0_TxCoeff6 0xcb8 -+#define rOFDM0_RxHPParameter 0xce0 -+#define rOFDM0_TxPseudoNoiseWgt 0xce4 -+#define rOFDM0_FrameSync 0xcf0 -+#define rOFDM0_DFSReport 0xcf4 -+ -+/* -+ * 7. PageD(0xD00) -+ * */ -+#define rOFDM1_LSTF 0xd00 -+#define rOFDM1_TRxPathEnable 0xd04 -+ -+/* -+ * 8. PageE(0xE00) -+ * */ -+#define rTxAGC_A_Rate18_06 0xe00 -+#define rTxAGC_A_Rate54_24 0xe04 -+#define rTxAGC_A_CCK1_Mcs32 0xe08 -+#define rTxAGC_A_Mcs03_Mcs00 0xe10 -+#define rTxAGC_A_Mcs07_Mcs04 0xe14 -+#define rTxAGC_A_Mcs11_Mcs08 0xe18 -+#define rTxAGC_A_Mcs15_Mcs12 0xe1c -+ -+#define rTxAGC_B_Rate18_06 0x830 -+#define rTxAGC_B_Rate54_24 0x834 -+#define rTxAGC_B_CCK1_55_Mcs32 0x838 -+#define rTxAGC_B_Mcs03_Mcs00 0x83c -+#define rTxAGC_B_Mcs07_Mcs04 0x848 -+#define rTxAGC_B_Mcs11_Mcs08 0x84c -+#define rTxAGC_B_Mcs15_Mcs12 0x868 -+#define rTxAGC_B_CCK11_A_CCK2_11 0x86c -+ -+#define rFPGA0_IQK 0xe28 -+#define rTx_IQK_Tone_A 0xe30 -+#define rRx_IQK_Tone_A 0xe34 -+#define rTx_IQK_PI_A 0xe38 -+#define rRx_IQK_PI_A 0xe3c -+ -+#define rTx_IQK 0xe40 -+#define rRx_IQK 0xe44 -+#define rIQK_AGC_Pts 0xe48 -+#define rIQK_AGC_Rsp 0xe4c -+#define rTx_IQK_Tone_B 0xe50 -+#define rRx_IQK_Tone_B 0xe54 -+#define rTx_IQK_PI_B 0xe58 -+#define rRx_IQK_PI_B 0xe5c -+#define rIQK_AGC_Cont 0xe60 -+ -+#define rBlue_Tooth 0xe6c -+#define rRx_Wait_CCA 0xe70 -+#define rTx_CCK_RFON 0xe74 -+#define rTx_CCK_BBON 0xe78 -+#define rTx_OFDM_RFON 0xe7c -+#define rTx_OFDM_BBON 0xe80 -+#define rTx_To_Rx 0xe84 -+#define rTx_To_Tx 0xe88 -+#define rRx_CCK 0xe8c -+ -+#define rTx_Power_Before_IQK_A 0xe94 -+#define rTx_Power_After_IQK_A 0xe9c -+ -+#define rRx_Power_Before_IQK_A 0xea0 -+#define rRx_Power_Before_IQK_A_2 0xea4 -+#define rRx_Power_After_IQK_A 0xea8 -+#define rRx_Power_After_IQK_A_2 0xeac -+ -+#define rTx_Power_Before_IQK_B 0xeb4 -+#define rTx_Power_After_IQK_B 0xebc -+ -+#define rRx_Power_Before_IQK_B 0xec0 -+#define rRx_Power_Before_IQK_B_2 0xec4 -+#define rRx_Power_After_IQK_B 0xec8 -+#define rRx_Power_After_IQK_B_2 0xecc -+ -+#define rRx_OFDM 0xed0 -+#define rRx_Wait_RIFS 0xed4 -+#define rRx_TO_Rx 0xed8 -+#define rStandby 0xedc -+#define rSleep 0xee0 -+#define rPMPD_ANAEN 0xeec -+ -+ -+/* 2. Page8(0x800) */ -+#define bRFMOD 0x1 /* Reg 0x800 rFPGA0_RFMOD */ -+#define bJapanMode 0x2 -+#define bCCKTxSC 0x30 -+#define bCCKEn 0x1000000 -+#define bOFDMEn 0x2000000 -+#define bXBTxAGC 0xf00 /* Reg 80c rFPGA0_TxGainStage */ -+#define bXCTxAGC 0xf000 -+#define bXDTxAGC 0xf0000 -+ -+/* 4. PageA(0xA00) */ -+#define bCCKBBMode 0x3 /* Useless */ -+#define bCCKTxPowerSaving 0x80 -+#define bCCKRxPowerSaving 0x40 -+ -+#define bCCKSideBand 0x10 /* Reg 0xa00 rCCK0_System 20/40 switch */ -+ -+#define bCCKScramble 0x8 /* Useless */ -+#define bCCKAntDiversity 0x8000 -+#define bCCKCarrierRecovery 0x4000 -+#define bCCKTxRate 0x3000 -+#define bCCKDCCancel 0x0800 -+#define bCCKISICancel 0x0400 -+#define bCCKMatchFilter 0x0200 -+#define bCCKEqualizer 0x0100 -+#define bCCKPreambleDetect 0x800000 -+#define bCCKFastFalseCCA 0x400000 -+#define bCCKChEstStart 0x300000 -+#define bCCKCCACount 0x080000 -+#define bCCKcs_lim 0x070000 -+#define bCCKBistMode 0x80000000 -+#define bCCKCCAMask 0x40000000 -+#define bCCKTxDACPhase 0x4 -+#define bCCKRxADCPhase 0x20000000 /* r_rx_clk */ -+#define bCCKr_cp_mode0 0x0100 -+#define bCCKTxDCOffset 0xf0 -+#define bCCKRxDCOffset 0xf -+#define bCCKCCAMode 0xc000 -+#define bCCKFalseCS_lim 0x3f00 -+#define bCCKCS_ratio 0xc00000 -+#define bCCKCorgBit_sel 0x300000 -+#define bCCKPD_lim 0x0f0000 -+#define bCCKNewCCA 0x80000000 -+#define bCCKRxHPofIG 0x8000 -+#define bCCKRxIG 0x7f00 -+#define bCCKLNAPolarity 0x800000 -+#define bCCKRx1stGain 0x7f0000 -+#define bCCKRFExtend 0x20000000 /* CCK Rx Iinital gain polarity */ -+#define bCCKRxAGCSatLevel 0x1f000000 -+#define bCCKRxAGCSatCount 0xe0 -+#define bCCKRxRFSettle 0x1f /* AGCsamp_dly */ -+#define bCCKFixedRxAGC 0x8000 -+/* #define bCCKRxAGCFormat 0x4000 */ /* remove to HSSI register 0x824 */ -+#define bCCKAntennaPolarity 0x2000 -+#define bCCKTxFilterType 0x0c00 -+#define bCCKRxAGCReportType 0x0300 -+#define bCCKRxDAGCEn 0x80000000 -+#define bCCKRxDAGCPeriod 0x20000000 -+#define bCCKRxDAGCSatLevel 0x1f000000 -+#define bCCKTimingRecovery 0x800000 -+#define bCCKTxC0 0x3f0000 -+#define bCCKTxC1 0x3f000000 -+#define bCCKTxC2 0x3f -+#define bCCKTxC3 0x3f00 -+#define bCCKTxC4 0x3f0000 -+#define bCCKTxC5 0x3f000000 -+#define bCCKTxC6 0x3f -+#define bCCKTxC7 0x3f00 -+#define bCCKDebugPort 0xff0000 -+#define bCCKDACDebug 0x0f000000 -+#define bCCKFalseAlarmEnable 0x8000 -+#define bCCKFalseAlarmRead 0x4000 -+#define bCCKTRSSI 0x7f -+#define bCCKRxAGCReport 0xfe -+#define bCCKRxReport_AntSel 0x80000000 -+#define bCCKRxReport_MFOff 0x40000000 -+#define bCCKRxRxReport_SQLoss 0x20000000 -+#define bCCKRxReport_Pktloss 0x10000000 -+#define bCCKRxReport_Lockedbit 0x08000000 -+#define bCCKRxReport_RateError 0x04000000 -+#define bCCKRxReport_RxRate 0x03000000 -+#define bCCKRxFACounterLower 0xff -+#define bCCKRxFACounterUpper 0xff000000 -+#define bCCKRxHPAGCStart 0xe000 -+#define bCCKRxHPAGCFinal 0x1c00 -+#define bCCKRxFalseAlarmEnable 0x8000 -+#define bCCKFACounterFreeze 0x4000 -+#define bCCKTxPathSel 0x10000000 -+#define bCCKDefaultRxPath 0xc000000 -+#define bCCKOptionRxPath 0x3000000 -+ -+/* 6. PageE(0xE00) */ -+#define bSTBCEn 0x4 /* Useless */ -+#define bAntennaMapping 0x10 -+#define bNss 0x20 -+#define bCFOAntSumD 0x200 -+#define bPHYCounterReset 0x8000000 -+#define bCFOReportGet 0x4000000 -+#define bOFDMContinueTx 0x10000000 -+#define bOFDMSingleCarrier 0x20000000 -+#define bOFDMSingleTone 0x40000000 -+ -+ -+/* -+ * Other Definition -+ * */ -+ -+#define bEnable 0x1 /* Useless */ -+#define bDisable 0x0 -+ -+/* byte endable for srwrite */ -+#define bByte0 0x1 /* Useless */ -+#define bByte1 0x2 -+#define bByte2 0x4 -+#define bByte3 0x8 -+#define bWord0 0x3 -+#define bWord1 0xc -+#define bDWord 0xf -+ -+/* for PutRegsetting & GetRegSetting BitMask */ -+#define bMaskByte0 0xff /* Reg 0xc50 rOFDM0_XAAGCCore~0xC6f */ -+#define bMaskByte1 0xff00 -+#define bMaskByte2 0xff0000 -+#define bMaskByte3 0xff000000 -+#define bMaskHWord 0xffff0000 -+#define bMaskLWord 0x0000ffff -+#define bMaskDWord 0xffffffff -+#define bMaskH3Bytes 0xffffff00 -+#define bMask12Bits 0xfff -+#define bMaskH4Bits 0xf0000000 -+#define bMaskOFDM_D 0xffc00000 -+#define bMaskCCK 0x3f3f3f3f -+ -+ -+/*--------------------------Define Parameters-------------------------------*/ -+ -+ -+#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/Hal8812PwrSeq.h linux-5.8/3rdparty/rtl8812au/include/Hal8812PwrSeq.h -new file mode 100644 -index 000000000..498faf811 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/Hal8812PwrSeq.h -@@ -0,0 +1,208 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+ -+ -+#ifndef __HAL8812PWRSEQ_H__ -+#define __HAL8812PWRSEQ_H__ -+ -+#include "HalPwrSeqCmd.h" -+ -+/* -+ Check document WB-110628-DZ-RTL8195 (Jaguar) Power Architecture-R04.pdf -+ There are 6 HW Power States: -+ 0: POFF--Power Off -+ 1: PDN--Power Down -+ 2: CARDEMU--Card Emulation -+ 3: ACT--Active Mode -+ 4: LPS--Low Power State -+ 5: SUS--Suspend -+ -+ The transision from different states are defined below -+ TRANS_CARDEMU_TO_ACT -+ TRANS_ACT_TO_CARDEMU -+ TRANS_CARDEMU_TO_SUS -+ TRANS_SUS_TO_CARDEMU -+ TRANS_CARDEMU_TO_PDN -+ TRANS_ACT_TO_LPS -+ TRANS_LPS_TO_ACT -+ -+ TRANS_END -+*/ -+#define RTL8812_TRANS_CARDEMU_TO_ACT_STEPS 15 -+#define RTL8812_TRANS_ACT_TO_CARDEMU_STEPS 15 -+#define RTL8812_TRANS_CARDEMU_TO_SUS_STEPS 15 -+#define RTL8812_TRANS_SUS_TO_CARDEMU_STEPS 15 -+#define RTL8812_TRANS_CARDEMU_TO_PDN_STEPS 15 -+#define RTL8812_TRANS_PDN_TO_CARDEMU_STEPS 15 -+#define RTL8812_TRANS_ACT_TO_LPS_STEPS 15 -+#define RTL8812_TRANS_LPS_TO_ACT_STEPS 15 -+#define RTL8812_TRANS_END_STEPS 1 -+ -+ -+#define RTL8812_TRANS_CARDEMU_TO_ACT \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, 0},/* disable SW LPS 0x04[10]=0*/ \ -+ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT1, BIT1},/* wait till 0x04[17] = 1 power ready*/ \ -+ /*{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0}, disable HWPDN 0x04[15]=0*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3, 0},/* disable WL suspend*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/* polling until return 0*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT0, 0},/**/ \ -+ {0x0024, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT1, 0}, /* 0x24[1] Choose the type of buffer after xosc: nand*/ \ -+ {0x0028, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3, 0}, /* 0x28[33] Choose the type of buffer after xosc: nand*/ -+ -+#define RTL8812_TRANS_ACT_TO_CARDEMU \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ {0x0c00, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x04}, /* 0xc00[7:0] = 4 turn off 3-wire */ \ -+ {0x0e00, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x04}, /* 0xe00[7:0] = 4 turn off 3-wire */ \ -+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0}, /* 0x2[0] = 0 RESET BB, CLOSE RF */ \ -+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US},/*Delay 1us*/ \ -+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0}, /* Whole BB is reset*/ \ -+ /*{0x001F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},//0x1F[7:0] = 0 turn off RF*/ \ -+ /*{0x004E, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0},//0x4C[23] = 0x4E[7] = 0, switch DPDT_SEL_P output from register 0x65[2] */ \ -+ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x2A}, /* 0x07[7:0] = 0x28 sps pwm mode 0x2a for BT coex*/ \ -+ {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x02, 0},/*0x8[1] = 0 ANA clk = 500k */ \ -+ /*{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0 | BIT1, 0}, // 0x02[1:0] = 0 reset BB */ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1}, /*0x04[9] = 1 turn off MAC by HW state machine*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT1, 0}, /*wait till 0x04[9] = 0 polling until return 0 to disable*/ -+ -+#define RTL8812_TRANS_CARDEMU_TO_SUS \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ {0x0042, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xF0, 0xcc},\ -+ {0x0042, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xF0, 0xEC},\ -+ {0x0043, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x07},/* gpio11 input mode, gpio10~8 output mode */ \ -+ {0x0045, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00},/* gpio 0~7 output same value as input ?? */ \ -+ {0x0046, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xff},/* gpio0~7 output mode */ \ -+ {0x0047, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/* 0x47[7:0] = 00 gpio mode */ \ -+ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/* suspend option all off */ \ -+ {0x0014, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x80, BIT7},/*0x14[7] = 1 turn on ZCD */ \ -+ {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x01, BIT0},/* 0x15[0] =1 trun on ZCD */ \ -+ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x10, BIT4},/*0x23[4] = 1 hpon LDO sleep mode */ \ -+ {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x02, 0},/*0x8[1] = 0 ANA clk = 500k */ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3, BIT3}, /*0x04[11] = 2b'11 enable WL suspend for PCIe*/ -+ -+#define RTL8812_TRANS_SUS_TO_CARDEMU \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3, 0}, /*0x04[11] = 2b'01enable WL suspend*/ \ -+ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x10, 0},/*0x23[4] = 0 hpon LDO sleep mode leave */ \ -+ {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x01, 0},/* 0x15[0] =0 trun off ZCD */ \ -+ {0x0014, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x80, 0},/*0x14[7] = 0 turn off ZCD */ \ -+ {0x0046, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00},/* gpio0~7 input mode */ \ -+ {0x0043, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00},/* gpio11 input mode, gpio10~8 input mode */ -+ -+#define RTL8812_TRANS_CARDEMU_TO_CARDDIS \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ /**{0x0194, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0}, //0x194[0]=0 , disable 32K clock*/ \ -+ /**{0x0093, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x94}, //0x93 = 0x94 , 90[30] =0 enable 500k ANA clock .switch clock from 12M to 500K , 90 [26] =0 disable EEprom loader clock*/ \ -+ {0x0003, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, 0}, /*0x03[2] = 0, reset 8051*/ \ -+ {0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x05}, /*0x80 = 05h if reload fw, fill the default value of host_CPU handshake field*/ \ -+ {0x0042, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xF0, 0xcc},\ -+ {0x0042, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xF0, 0xEC},\ -+ {0x0043, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x07},/* gpio11 input mode, gpio10~8 output mode */ \ -+ {0x0045, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00},/* gpio 0~7 output same value as input ?? */ \ -+ {0x0046, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xff},/* gpio0~7 output mode */ \ -+ {0x0047, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/* 0x47[7:0] = 00 gpio mode */ \ -+ {0x0014, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x80, BIT7},/*0x14[7] = 1 turn on ZCD */ \ -+ {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x01, BIT0},/* 0x15[0] =1 trun on ZCD */ \ -+ {0x0012, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x01, 0},/*0x12[0] = 0 force PFM mode */ \ -+ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x10, BIT4},/*0x23[4] = 1 hpon LDO sleep mode */ \ -+ {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x02, 0},/*0x8[1] = 0 ANA clk = 500k */ \ -+ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07 = 0x20 , SOP option to disable BG/MB*/ \ -+ {0x001f, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0}, /*0x01f[1]=0 , disable RFC_0 control REG_RF_CTRL_8812 */ \ -+ {0x0076, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0}, /*0x076[1]=0 , disable RFC_1 control REG_OPT_CTRL_8812 +2 */ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3, BIT3}, /*0x04[11] = 2b'01 enable WL suspend*/ -+ -+#define RTL8812_TRANS_CARDDIS_TO_CARDEMU \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ {0x0012, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/*0x12[0] = 1 force PWM mode */ \ -+ {0x0014, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x80, 0},/*0x14[7] = 0 turn off ZCD */ \ -+ {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x01, 0},/* 0x15[0] =0 trun off ZCD */ \ -+ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x10, 0},/*0x23[4] = 0 hpon LDO leave sleep mode */ \ -+ {0x0046, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00},/* gpio0~7 input mode */ \ -+ {0x0043, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00},/* gpio11 input mode, gpio10~8 input mode */ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, 0}, /*0x04[10] = 0, enable SW LPS PCIE only*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3, 0}, /*0x04[11] = 2b'01enable WL suspend*/ \ -+ {0x0003, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, BIT2}, /*0x03[2] = 1, enable 8051*/ \ -+ {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/*PCIe DMA start*/ \ -+ {0x0024, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT1, BIT1}, /* 0x24[1] Choose the type of buffer after xosc: schmitt trigger*/ \ -+ {0x0028, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3, BIT3}, /* 0x28[33] Choose the type of buffer after xosc: schmitt trigger*/ -+ -+ -+#define RTL8812_TRANS_CARDEMU_TO_PDN \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, BIT7},/* 0x04[15] = 1*/ -+ -+#define RTL8812_TRANS_PDN_TO_CARDEMU \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0},/* 0x04[15] = 0*/ -+ -+#define RTL8812_TRANS_ACT_TO_LPS \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF},/*PCIe DMA stop*/ \ -+ {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x7F},/*Tx Pause*/ \ -+ {0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ -+ {0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ -+ {0x05FA, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ -+ {0x05FB, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ -+ {0x0c00, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x04}, /* 0xc00[7:0] = 4 turn off 3-wire */ \ -+ {0x0e00, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x04}, /* 0xe00[7:0] = 4 turn off 3-wire */ \ -+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0},/*CCK and OFDM are disabled, and clock are gated, and RF closed*/ \ -+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US},/*Delay 1us*/ \ -+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0}, /* Whole BB is reset*/ \ -+ {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x03},/*Reset MAC TRX*/ \ -+ {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0},/*check if removed later*/ \ -+ {0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, BIT5},/*Respond TxOK to scheduler*/ -+ -+ -+#define RTL8812_TRANS_LPS_TO_ACT \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ {0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, 0xFF, 0x84}, /*SDIO RPWM*/ \ -+ {0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*USB RPWM*/ \ -+ {0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*PCIe RPWM*/ \ -+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS}, /*Delay*/ \ -+ {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*. 0x08[4] = 0 switch TSF to 40M*/ \ -+ {0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT7, 0}, /*Polling 0x109[7]=0 TSF in 40M*/ \ -+ {0x0029, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6 | BIT7, 0}, /*. 0x29[7:6] = 2b'00 enable BB clock*/ \ -+ {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1}, /*. 0x101[1] = 1*/ \ -+ {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF}, /*. 0x100[7:0] = 0xFF enable WMAC TRX*/ \ -+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1 | BIT0, BIT1 | BIT0}, /*. 0x02[1:0] = 2b'11 enable BB macro*/ \ -+ {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}, /*. 0x522 = 0*/ -+ -+#define RTL8812_TRANS_END \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ {0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, 0, PWR_CMD_END, 0, 0}, -+ -+ -+extern WLAN_PWR_CFG rtl8812_power_on_flow[RTL8812_TRANS_CARDEMU_TO_ACT_STEPS + RTL8812_TRANS_END_STEPS]; -+extern WLAN_PWR_CFG rtl8812_radio_off_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS + RTL8812_TRANS_END_STEPS]; -+extern WLAN_PWR_CFG rtl8812_card_disable_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS + RTL8812_TRANS_CARDEMU_TO_PDN_STEPS + RTL8812_TRANS_END_STEPS]; -+extern WLAN_PWR_CFG rtl8812_card_enable_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS + RTL8812_TRANS_CARDEMU_TO_PDN_STEPS + RTL8812_TRANS_END_STEPS]; -+extern WLAN_PWR_CFG rtl8812_suspend_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS + RTL8812_TRANS_CARDEMU_TO_SUS_STEPS + RTL8812_TRANS_END_STEPS]; -+extern WLAN_PWR_CFG rtl8812_resume_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS + RTL8812_TRANS_CARDEMU_TO_SUS_STEPS + RTL8812_TRANS_END_STEPS]; -+extern WLAN_PWR_CFG rtl8812_hwpdn_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS + RTL8812_TRANS_CARDEMU_TO_PDN_STEPS + RTL8812_TRANS_END_STEPS]; -+extern WLAN_PWR_CFG rtl8812_enter_lps_flow[RTL8812_TRANS_ACT_TO_LPS_STEPS + RTL8812_TRANS_END_STEPS]; -+extern WLAN_PWR_CFG rtl8812_leave_lps_flow[RTL8812_TRANS_LPS_TO_ACT_STEPS + RTL8812_TRANS_END_STEPS]; -+ -+#endif /* __HAL8812PWRSEQ_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/Hal8814PhyCfg.h linux-5.8/3rdparty/rtl8812au/include/Hal8814PhyCfg.h -new file mode 100644 -index 000000000..96f07942e ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/Hal8814PhyCfg.h -@@ -0,0 +1,264 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+#ifndef __INC_HAL8814PHYCFG_H__ -+#define __INC_HAL8814PHYCFG_H__ -+ -+ -+/*--------------------------Define Parameters-------------------------------*/ -+#define LOOP_LIMIT 5 -+#define MAX_STALL_TIME 50 /* us */ -+#define AntennaDiversityValue 0x80 /* (Adapter->bSoftwareAntennaDiversity ? 0x00 : 0x80) */ -+#define MAX_TXPWR_IDX_NMODE_92S 63 -+#define Reset_Cnt_Limit 3 -+ -+ -+#ifdef CONFIG_PCI_HCI -+ #define MAX_AGGR_NUM 0x0B -+#else -+ #define MAX_AGGR_NUM 0x07 -+#endif /* CONFIG_PCI_HCI */ -+ -+ -+/*--------------------------Define Parameters-------------------------------*/ -+ -+/*------------------------------Define structure----------------------------*/ -+ -+ -+/* BB/RF related */ -+ -+#define SIC_ENABLE 0 -+ -+/*------------------------------Define structure----------------------------*/ -+ -+ -+/*------------------------Export global variable----------------------------*/ -+/*------------------------Export global variable----------------------------*/ -+ -+ -+/*------------------------Export Marco Definition---------------------------*/ -+/*------------------------Export Marco Definition---------------------------*/ -+ -+ -+/*--------------------------Exported Function prototype---------------------*/ -+/* 1. BB register R/W API */ -+ -+extern u32 -+PHY_QueryBBReg8814A(IN PADAPTER Adapter, -+ IN u32 RegAddr, -+ IN u32 BitMask); -+ -+ -+VOID -+PHY_SetBBReg8814A(IN PADAPTER Adapter, -+ IN u32 RegAddr, -+ IN u32 BitMask, -+ IN u32 Data); -+ -+ -+extern u32 -+PHY_QueryRFReg8814A(IN PADAPTER Adapter, -+ IN enum rf_path eRFPath, -+ IN u32 RegAddr, -+ IN u32 BitMask); -+ -+ -+void -+PHY_SetRFReg8814A(IN PADAPTER Adapter, -+ IN enum rf_path eRFPath, -+ IN u32 RegAddr, -+ IN u32 BitMask, -+ IN u32 Data); -+ -+/* 1 3. Initial BB/RF config by reading MAC/BB/RF txt. */ -+s32 -+phy_BB8814A_Config_ParaFile( -+ IN PADAPTER Adapter -+); -+ -+VOID -+PHY_ConfigBB_8814A( -+ IN PADAPTER Adapter -+); -+ -+ -+VOID -+phy_ADC_CLK_8814A( -+ IN PADAPTER Adapter -+); -+ -+s32 -+PHY_RFConfig8814A( -+ IN PADAPTER Adapter -+); -+ -+/* -+ * RF Power setting -+ * -+ * BOOLEAN PHY_SetRFPowerState8814A(PADAPTER Adapter, rt_rf_power_state eRFPowerState); */ -+ -+/* 1 5. Tx Power setting API */ -+ -+VOID -+PHY_GetTxPowerLevel8814( -+ IN PADAPTER Adapter, -+ OUT ps4Byte powerlevel -+); -+ -+VOID -+PHY_SetTxPowerLevel8814( -+ IN PADAPTER Adapter, -+ IN u8 Channel -+); -+ -+u8 -+phy_get_tx_power_index_8814a( -+ IN PADAPTER Adapter, -+ IN enum rf_path RFPath, -+ IN u8 Rate, -+ IN enum channel_width BandWidth, -+ IN u8 Channel -+); -+ -+u8 -+PHY_GetTxPowerIndex8814A( -+ IN PADAPTER Adapter, -+ IN enum rf_path RFPath, -+ IN u8 Rate, -+ IN u8 BandWidth, -+ IN u8 Channel, -+ struct txpwr_idx_comp *tic -+); -+ -+VOID -+PHY_SetTxPowerIndex_8814A( -+ IN PADAPTER Adapter, -+ IN u32 PowerIndex, -+ IN enum rf_path RFPath, -+ IN u8 Rate -+); -+ -+ -+BOOLEAN -+PHY_UpdateTxPowerDbm8814A( -+ IN PADAPTER Adapter, -+ IN s4Byte powerInDbm -+); -+ -+ -+u32 -+PHY_GetTxBBSwing_8814A( -+ IN PADAPTER Adapter, -+ IN BAND_TYPE Band, -+ IN enum rf_path RFPath -+); -+ -+ -+ -+/* 1 6. Channel setting API */ -+#if 0 -+VOID -+PHY_SwChnlTimerCallback8814A( -+ IN struct timer_list *p_timer -+); -+#endif -+VOID -+PHY_SwChnlWorkItemCallback8814A( -+ IN PVOID pContext -+); -+ -+ -+VOID -+HAL_HandleSwChnl8814A( -+ IN PADAPTER pAdapter, -+ IN u8 channel -+); -+ -+VOID -+PHY_SwChnlSynchronously8814A(IN PADAPTER pAdapter, -+ IN u8 channel); -+ -+VOID -+PHY_SwChnlAndSetBWModeCallback8814A(IN PVOID pContext); -+ -+ -+VOID -+PHY_HandleSwChnlAndSetBW8814A( -+ IN PADAPTER Adapter, -+ IN BOOLEAN bSwitchChannel, -+ IN BOOLEAN bSetBandWidth, -+ IN u8 ChannelNum, -+ IN enum channel_width ChnlWidth, -+ IN u8 ChnlOffsetOf40MHz, -+ IN u8 ChnlOffsetOf80MHz, -+ IN u8 CenterFrequencyIndex1 -+); -+ -+ -+BOOLEAN -+PHY_QueryRFPathSwitch_8814A(IN PADAPTER pAdapter); -+ -+ -+ -+#if (USE_WORKITEM) -+VOID -+RtCheckForHangWorkItemCallback8814A( -+ IN PVOID pContext -+); -+#endif -+ -+BOOLEAN -+SetAntennaConfig8814A( -+ IN PADAPTER Adapter, -+ IN u8 DefaultAnt -+); -+ -+VOID -+PHY_SetRFEReg8814A( -+ IN PADAPTER Adapter, -+ IN BOOLEAN bInit, -+ IN u8 Band -+); -+ -+ -+s32 -+PHY_SwitchWirelessBand8814A( -+ IN PADAPTER Adapter, -+ IN u8 Band -+); -+ -+VOID -+PHY_SetIO_8814A( -+ PADAPTER pAdapter -+); -+ -+VOID -+PHY_SetSwChnlBWMode8814( -+ IN PADAPTER Adapter, -+ IN u8 channel, -+ IN enum channel_width Bandwidth, -+ IN u8 Offset40, -+ IN u8 Offset80 -+); -+ -+s32 PHY_MACConfig8814(PADAPTER Adapter); -+int PHY_BBConfig8814(PADAPTER Adapter); -+VOID PHY_Set_SecCCATH_by_RXANT_8814A(PADAPTER pAdapter, u4Byte ulAntennaRx); -+ -+ -+ -+/*--------------------------Exported Function prototype---------------------*/ -+ -+/*--------------------------Exported Function prototype---------------------*/ -+#endif /* __INC_HAL8192CPHYCFG_H */ -diff --git linux-5.8/3rdparty/rtl8812au/include/Hal8814PhyReg.h linux-5.8/3rdparty/rtl8812au/include/Hal8814PhyReg.h -new file mode 100644 -index 000000000..21851a898 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/Hal8814PhyReg.h -@@ -0,0 +1,863 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+#ifndef __INC_HAL8814PHYREG_H__ -+#define __INC_HAL8814PHYREG_H__ -+/*--------------------------Define Parameters-------------------------------*/ -+/* -+ * BB-PHY register PMAC 0x100 PHY 0x800 - 0xEFF -+ * 1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF -+ * 2. 0x800/0x900/0xA00/0xC00/0xD00/0xE00 -+ * 3. RF register 0x00-2E -+ * 4. Bit Mask for BB/RF register -+ * 5. Other defintion for BB/RF R/W -+ * */ -+ -+ -+/* BB Register Definition */ -+ -+#define rCCAonSec_Jaguar 0x838 -+#define rPwed_TH_Jaguar 0x830 -+#define rL1_Weight_Jaguar 0x840 -+#define r_L1_SBD_start_time 0x844 -+ -+/* BW and sideband setting */ -+#define rBWIndication_Jaguar 0x834 -+#define rL1PeakTH_Jaguar 0x848 -+#define rRFMOD_Jaguar 0x8ac /* RF mode */ -+#define rADC_Buf_Clk_Jaguar 0x8c4 -+#define rADC_Buf_40_Clk_Jaguar2 0x8c8 -+#define rRFECTRL_Jaguar 0x900 -+#define bRFMOD_Jaguar 0xc3 -+#define rCCK_System_Jaguar 0xa00 /* for cck sideband */ -+#define bCCK_System_Jaguar 0x10 -+ -+/* Block & Path enable */ -+#define rOFDMCCKEN_Jaguar 0x808 /* OFDM/CCK block enable */ -+#define bOFDMEN_Jaguar 0x20000000 -+#define bCCKEN_Jaguar 0x10000000 -+#define rRxPath_Jaguar 0x808 /* Rx antenna */ -+#define bRxPath_Jaguar 0xff -+#define rTxPath_Jaguar 0x80c /* Tx antenna */ -+#define bTxPath_Jaguar 0x0fffffff -+#define rCCK_RX_Jaguar 0xa04 /* for cck rx path selection */ -+#define bCCK_RX_Jaguar 0x0c000000 -+#define rVhtlen_Use_Lsig_Jaguar 0x8c3 /* Use LSIG for VHT length */ -+ -+#define rRxPath_Jaguar2 0xa04 /* Rx antenna */ -+#define rTxAnt_1Nsts_Jaguar2 0x93c /* Tx antenna for 1Nsts */ -+#define rTxAnt_23Nsts_Jaguar2 0x940 /* Tx antenna for 2Nsts and 3Nsts */ -+ -+ -+/* RF read/write-related */ -+#define rHSSIRead_Jaguar 0x8b0 /* RF read addr */ -+#define bHSSIRead_addr_Jaguar 0xff -+#define bHSSIRead_trigger_Jaguar 0x100 -+#define rA_PIRead_Jaguar 0xd04 /* RF readback with PI */ -+#define rB_PIRead_Jaguar 0xd44 /* RF readback with PI */ -+#define rA_SIRead_Jaguar 0xd08 /* RF readback with SI */ -+#define rB_SIRead_Jaguar 0xd48 /* RF readback with SI */ -+#define rRead_data_Jaguar 0xfffff -+#define rA_LSSIWrite_Jaguar 0xc90 /* RF write addr */ -+#define rB_LSSIWrite_Jaguar 0xe90 /* RF write addr */ -+#define bLSSIWrite_data_Jaguar 0x000fffff -+#define bLSSIWrite_addr_Jaguar 0x0ff00000 -+ -+#define rC_PIRead_Jaguar2 0xd84 /* RF readback with PI */ -+#define rD_PIRead_Jaguar2 0xdC4 /* RF readback with PI */ -+#define rC_SIRead_Jaguar2 0xd88 /* RF readback with SI */ -+#define rD_SIRead_Jaguar2 0xdC8 /* RF readback with SI */ -+#define rC_LSSIWrite_Jaguar2 0x1890 /* RF write addr */ -+#define rD_LSSIWrite_Jaguar2 0x1A90 /* RF write addr */ -+ -+ -+/* YN: mask the following register definition temporarily */ -+#define rFPGA0_XA_RFInterfaceOE 0x860 /* RF Channel switch */ -+#define rFPGA0_XB_RFInterfaceOE 0x864 -+ -+#define rFPGA0_XAB_RFInterfaceSW 0x870 /* RF Interface Software Control */ -+#define rFPGA0_XCD_RFInterfaceSW 0x874 -+ -+/* #define rFPGA0_XAB_RFParameter 0x878 */ /* RF Parameter -+ * #define rFPGA0_XCD_RFParameter 0x87c */ -+ -+/* #define rFPGA0_AnalogParameter1 0x880 */ /* Crystal cap setting RF-R/W protection for parameter4?? -+ * #define rFPGA0_AnalogParameter2 0x884 -+ * #define rFPGA0_AnalogParameter3 0x888 -+ * #define rFPGA0_AdDaClockEn 0x888 */ /* enable ad/da clock1 for dual-phy -+ * #define rFPGA0_AnalogParameter4 0x88c */ -+ -+ -+/* CCK TX scaling */ -+#define rCCK_TxFilter1_Jaguar 0xa20 -+#define bCCK_TxFilter1_C0_Jaguar 0x00ff0000 -+#define bCCK_TxFilter1_C1_Jaguar 0xff000000 -+#define rCCK_TxFilter2_Jaguar 0xa24 -+#define bCCK_TxFilter2_C2_Jaguar 0x000000ff -+#define bCCK_TxFilter2_C3_Jaguar 0x0000ff00 -+#define bCCK_TxFilter2_C4_Jaguar 0x00ff0000 -+#define bCCK_TxFilter2_C5_Jaguar 0xff000000 -+#define rCCK_TxFilter3_Jaguar 0xa28 -+#define bCCK_TxFilter3_C6_Jaguar 0x000000ff -+#define bCCK_TxFilter3_C7_Jaguar 0x0000ff00 -+/* NBI & CSI Mask setting */ -+#define rCSI_Mask_Setting1_Jaguar 0x874 -+#define rCSI_Fix_Mask0_Jaguar 0x880 -+#define rCSI_Fix_Mask1_Jaguar 0x884 -+#define rCSI_Fix_Mask2_Jaguar 0x888 -+#define rCSI_Fix_Mask3_Jaguar 0x88c -+#define rCSI_Fix_Mask4_Jaguar 0x890 -+#define rCSI_Fix_Mask5_Jaguar 0x894 -+#define rCSI_Fix_Mask6_Jaguar 0x898 -+#define rCSI_Fix_Mask7_Jaguar 0x89c -+#define rNBI_Setting_Jaguar 0x87c -+ -+ -+/* YN: mask the following register definition temporarily -+ * #define rPdp_AntA 0xb00 -+ * #define rPdp_AntA_4 0xb04 -+ * #define rConfig_Pmpd_AntA 0xb28 -+ * #define rConfig_AntA 0xb68 -+ * #define rConfig_AntB 0xb6c -+ * #define rPdp_AntB 0xb70 -+ * #define rPdp_AntB_4 0xb74 -+ * #define rConfig_Pmpd_AntB 0xb98 -+ * #define rAPK 0xbd8 */ -+ -+/* RXIQC */ -+#define rA_RxIQC_AB_Jaguar 0xc10 /* RxIQ imblance matrix coeff. A & B */ -+#define rA_RxIQC_CD_Jaguar 0xc14 /* RxIQ imblance matrix coeff. C & D */ -+#define rA_TxScale_Jaguar 0xc1c /* Pah_A TX scaling factor */ -+#define rB_TxScale_Jaguar 0xe1c /* Path_B TX scaling factor */ -+#define rB_RxIQC_AB_Jaguar 0xe10 /* RxIQ imblance matrix coeff. A & B */ -+#define rB_RxIQC_CD_Jaguar 0xe14 /* RxIQ imblance matrix coeff. C & D */ -+#define b_RxIQC_AC_Jaguar 0x02ff /* bit mask for IQC matrix element A & C */ -+#define b_RxIQC_BD_Jaguar 0x02ff0000 /* bit mask for IQC matrix element A & C */ -+ -+#define rC_TxScale_Jaguar2 0x181c /* Pah_C TX scaling factor */ -+#define rD_TxScale_Jaguar2 0x1A1c /* Path_D TX scaling factor */ -+#define rRF_TxGainOffset 0x55 -+ -+/* DIG-related */ -+#define rA_IGI_Jaguar 0xc50 /* Initial Gain for path-A */ -+#define rB_IGI_Jaguar 0xe50 /* Initial Gain for path-B */ -+#define rC_IGI_Jaguar2 0x1850 /* Initial Gain for path-C */ -+#define rD_IGI_Jaguar2 0x1A50 /* Initial Gain for path-D */ -+ -+#define rOFDM_FalseAlarm1_Jaguar 0xf48 /* counter for break */ -+#define rOFDM_FalseAlarm2_Jaguar 0xf4c /* counter for spoofing */ -+#define rCCK_FalseAlarm_Jaguar 0xa5c /* counter for cck false alarm */ -+#define b_FalseAlarm_Jaguar 0xffff -+#define rCCK_CCA_Jaguar 0xa08 /* cca threshold */ -+#define bCCK_CCA_Jaguar 0x00ff0000 -+ -+/* Tx Power Ttraining-related */ -+#define rA_TxPwrTraing_Jaguar 0xc54 -+#define rB_TxPwrTraing_Jaguar 0xe54 -+ -+/* Report-related */ -+#define rOFDM_ShortCFOAB_Jaguar 0xf60 -+#define rOFDM_LongCFOAB_Jaguar 0xf64 -+#define rOFDM_EndCFOAB_Jaguar 0xf70 -+#define rOFDM_AGCReport_Jaguar 0xf84 -+#define rOFDM_RxSNR_Jaguar 0xf88 -+#define rOFDM_RxEVMCSI_Jaguar 0xf8c -+#define rOFDM_SIGReport_Jaguar 0xf90 -+ -+/* Misc functions */ -+#define rEDCCA_Jaguar 0x8a4 /* EDCCA */ -+#define bEDCCA_Jaguar 0xffff -+#define rAGC_table_Jaguar 0x82c /* AGC tabel select */ -+#define bAGC_table_Jaguar 0x3 -+#define b_sel5g_Jaguar 0x1000 /* sel5g */ -+#define b_LNA_sw_Jaguar 0x8000 /* HW/WS control for LNA */ -+#define rFc_area_Jaguar 0x860 /* fc_area */ -+#define bFc_area_Jaguar 0x1ffe000 -+#define rSingleTone_ContTx_Jaguar 0x914 -+ -+#define rAGC_table_Jaguar2 0x958 /* AGC tabel select */ -+#define rDMA_trigger_Jaguar2 0x95C /* ADC sample mode */ -+ -+ -+/* RFE */ -+#define rA_RFE_Pinmux_Jaguar 0xcb0 /* Path_A RFE cotrol pinmux */ -+#define rB_RFE_Pinmux_Jaguar 0xeb0 /* Path_B RFE control pinmux */ -+#define rA_RFE_Inv_Jaguar 0xcb4 /* Path_A RFE cotrol */ -+#define rB_RFE_Inv_Jaguar 0xeb4 /* Path_B RFE control */ -+#define rA_RFE_Jaguar 0xcb8 /* Path_A RFE cotrol */ -+#define rB_RFE_Jaguar 0xeb8 /* Path_B RFE control */ -+#define rA_RFE_Inverse_Jaguar 0xCBC /* Path_A RFE control inverse */ -+#define rB_RFE_Inverse_Jaguar 0xEBC /* Path_B RFE control inverse */ -+#define r_ANTSEL_SW_Jaguar 0x900 /* ANTSEL SW Control */ -+#define bMask_RFEInv_Jaguar 0x3ff00000 -+#define bMask_AntselPathFollow_Jaguar 0x00030000 -+ -+#define rC_RFE_Pinmux_Jaguar 0x18B4 /* Path_C RFE cotrol pinmux */ -+#define rD_RFE_Pinmux_Jaguar 0x1AB4 /* Path_D RFE cotrol pinmux */ -+#define rA_RFE_Sel_Jaguar2 0x1990 -+ -+ -+ -+/* TX AGC */ -+#define rTxAGC_A_CCK11_CCK1_JAguar 0xc20 -+#define rTxAGC_A_Ofdm18_Ofdm6_JAguar 0xc24 -+#define rTxAGC_A_Ofdm54_Ofdm24_JAguar 0xc28 -+#define rTxAGC_A_MCS3_MCS0_JAguar 0xc2c -+#define rTxAGC_A_MCS7_MCS4_JAguar 0xc30 -+#define rTxAGC_A_MCS11_MCS8_JAguar 0xc34 -+#define rTxAGC_A_MCS15_MCS12_JAguar 0xc38 -+#define rTxAGC_A_Nss1Index3_Nss1Index0_JAguar 0xc3c -+#define rTxAGC_A_Nss1Index7_Nss1Index4_JAguar 0xc40 -+#define rTxAGC_A_Nss2Index1_Nss1Index8_JAguar 0xc44 -+#define rTxAGC_A_Nss2Index5_Nss2Index2_JAguar 0xc48 -+#define rTxAGC_A_Nss2Index9_Nss2Index6_JAguar 0xc4c -+#define rTxAGC_B_CCK11_CCK1_JAguar 0xe20 -+#define rTxAGC_B_Ofdm18_Ofdm6_JAguar 0xe24 -+#define rTxAGC_B_Ofdm54_Ofdm24_JAguar 0xe28 -+#define rTxAGC_B_MCS3_MCS0_JAguar 0xe2c -+#define rTxAGC_B_MCS7_MCS4_JAguar 0xe30 -+#define rTxAGC_B_MCS11_MCS8_JAguar 0xe34 -+#define rTxAGC_B_MCS15_MCS12_JAguar 0xe38 -+#define rTxAGC_B_Nss1Index3_Nss1Index0_JAguar 0xe3c -+#define rTxAGC_B_Nss1Index7_Nss1Index4_JAguar 0xe40 -+#define rTxAGC_B_Nss2Index1_Nss1Index8_JAguar 0xe44 -+#define rTxAGC_B_Nss2Index5_Nss2Index2_JAguar 0xe48 -+#define rTxAGC_B_Nss2Index9_Nss2Index6_JAguar 0xe4c -+#define bTxAGC_byte0_Jaguar 0xff -+#define bTxAGC_byte1_Jaguar 0xff00 -+#define bTxAGC_byte2_Jaguar 0xff0000 -+#define bTxAGC_byte3_Jaguar 0xff000000 -+ -+ -+/* TX AGC */ -+#define rTxAGC_A_CCK11_CCK1_Jaguar2 0xc20 -+#define rTxAGC_A_Ofdm18_Ofdm6_Jaguar2 0xc24 -+#define rTxAGC_A_Ofdm54_Ofdm24_Jaguar2 0xc28 -+#define rTxAGC_A_MCS3_MCS0_Jaguar2 0xc2c -+#define rTxAGC_A_MCS7_MCS4_Jaguar2 0xc30 -+#define rTxAGC_A_MCS11_MCS8_Jaguar2 0xc34 -+#define rTxAGC_A_MCS15_MCS12_Jaguar2 0xc38 -+#define rTxAGC_A_MCS19_MCS16_Jaguar2 0xcd8 -+#define rTxAGC_A_MCS23_MCS20_Jaguar2 0xcdc -+#define rTxAGC_A_Nss1Index3_Nss1Index0_Jaguar2 0xc3c -+#define rTxAGC_A_Nss1Index7_Nss1Index4_Jaguar2 0xc40 -+#define rTxAGC_A_Nss2Index1_Nss1Index8_Jaguar2 0xc44 -+#define rTxAGC_A_Nss2Index5_Nss2Index2_Jaguar2 0xc48 -+#define rTxAGC_A_Nss2Index9_Nss2Index6_Jaguar2 0xc4c -+#define rTxAGC_A_Nss3Index3_Nss3Index0_Jaguar2 0xce0 -+#define rTxAGC_A_Nss3Index7_Nss3Index4_Jaguar2 0xce4 -+#define rTxAGC_A_Nss3Index9_Nss3Index8_Jaguar2 0xce8 -+#define rTxAGC_B_CCK11_CCK1_Jaguar2 0xe20 -+#define rTxAGC_B_Ofdm18_Ofdm6_Jaguar2 0xe24 -+#define rTxAGC_B_Ofdm54_Ofdm24_Jaguar2 0xe28 -+#define rTxAGC_B_MCS3_MCS0_Jaguar2 0xe2c -+#define rTxAGC_B_MCS7_MCS4_Jaguar2 0xe30 -+#define rTxAGC_B_MCS11_MCS8_Jaguar2 0xe34 -+#define rTxAGC_B_MCS15_MCS12_Jaguar2 0xe38 -+#define rTxAGC_B_MCS19_MCS16_Jaguar2 0xed8 -+#define rTxAGC_B_MCS23_MCS20_Jaguar2 0xedc -+#define rTxAGC_B_Nss1Index3_Nss1Index0_Jaguar2 0xe3c -+#define rTxAGC_B_Nss1Index7_Nss1Index4_Jaguar2 0xe40 -+#define rTxAGC_B_Nss2Index1_Nss1Index8_Jaguar2 0xe44 -+#define rTxAGC_B_Nss2Index5_Nss2Index2_Jaguar2 0xe48 -+#define rTxAGC_B_Nss2Index9_Nss2Index6_Jaguar2 0xe4c -+#define rTxAGC_B_Nss3Index3_Nss3Index0_Jaguar2 0xee0 -+#define rTxAGC_B_Nss3Index7_Nss3Index4_Jaguar2 0xee4 -+#define rTxAGC_B_Nss3Index9_Nss3Index8_Jaguar2 0xee8 -+#define rTxAGC_C_CCK11_CCK1_Jaguar2 0x1820 -+#define rTxAGC_C_Ofdm18_Ofdm6_Jaguar2 0x1824 -+#define rTxAGC_C_Ofdm54_Ofdm24_Jaguar2 0x1828 -+#define rTxAGC_C_MCS3_MCS0_Jaguar2 0x182c -+#define rTxAGC_C_MCS7_MCS4_Jaguar2 0x1830 -+#define rTxAGC_C_MCS11_MCS8_Jaguar2 0x1834 -+#define rTxAGC_C_MCS15_MCS12_Jaguar2 0x1838 -+#define rTxAGC_C_MCS19_MCS16_Jaguar2 0x18d8 -+#define rTxAGC_C_MCS23_MCS20_Jaguar2 0x18dc -+#define rTxAGC_C_Nss1Index3_Nss1Index0_Jaguar2 0x183c -+#define rTxAGC_C_Nss1Index7_Nss1Index4_Jaguar2 0x1840 -+#define rTxAGC_C_Nss2Index1_Nss1Index8_Jaguar2 0x1844 -+#define rTxAGC_C_Nss2Index5_Nss2Index2_Jaguar2 0x1848 -+#define rTxAGC_C_Nss2Index9_Nss2Index6_Jaguar2 0x184c -+#define rTxAGC_C_Nss3Index3_Nss3Index0_Jaguar2 0x18e0 -+#define rTxAGC_C_Nss3Index7_Nss3Index4_Jaguar2 0x18e4 -+#define rTxAGC_C_Nss3Index9_Nss3Index8_Jaguar2 0x18e8 -+#define rTxAGC_D_CCK11_CCK1_Jaguar2 0x1a20 -+#define rTxAGC_D_Ofdm18_Ofdm6_Jaguar2 0x1a24 -+#define rTxAGC_D_Ofdm54_Ofdm24_Jaguar2 0x1a28 -+#define rTxAGC_D_MCS3_MCS0_Jaguar2 0x1a2c -+#define rTxAGC_D_MCS7_MCS4_Jaguar2 0x1a30 -+#define rTxAGC_D_MCS11_MCS8_Jaguar2 0x1a34 -+#define rTxAGC_D_MCS15_MCS12_Jaguar2 0x1a38 -+#define rTxAGC_D_MCS19_MCS16_Jaguar2 0x1ad8 -+#define rTxAGC_D_MCS23_MCS20_Jaguar2 0x1adc -+#define rTxAGC_D_Nss1Index3_Nss1Index0_Jaguar2 0x1a3c -+#define rTxAGC_D_Nss1Index7_Nss1Index4_Jaguar2 0x1a40 -+#define rTxAGC_D_Nss2Index1_Nss1Index8_Jaguar2 0x1a44 -+#define rTxAGC_D_Nss2Index5_Nss2Index2_Jaguar2 0x1a48 -+#define rTxAGC_D_Nss2Index9_Nss2Index6_Jaguar2 0x1a4c -+#define rTxAGC_D_Nss3Index3_Nss3Index0_Jaguar2 0x1ae0 -+#define rTxAGC_D_Nss3Index7_Nss3Index4_Jaguar2 0x1ae4 -+#define rTxAGC_D_Nss3Index9_Nss3Index8_Jaguar2 0x1ae8 -+/* IQK YN: temporaily mask this part -+ * #define rFPGA0_IQK 0xe28 -+ * #define rTx_IQK_Tone_A 0xe30 -+ * #define rRx_IQK_Tone_A 0xe34 -+ * #define rTx_IQK_PI_A 0xe38 -+ * #define rRx_IQK_PI_A 0xe3c */ -+ -+/* #define rTx_IQK 0xe40 */ -+/* #define rRx_IQK 0xe44 */ -+/* #define rIQK_AGC_Pts 0xe48 */ -+/* #define rIQK_AGC_Rsp 0xe4c */ -+/* #define rTx_IQK_Tone_B 0xe50 */ -+/* #define rRx_IQK_Tone_B 0xe54 */ -+/* #define rTx_IQK_PI_B 0xe58 */ -+/* #define rRx_IQK_PI_B 0xe5c */ -+/* #define rIQK_AGC_Cont 0xe60 */ -+ -+ -+/* AFE-related */ -+#define rA_AFEPwr1_Jaguar 0xc60 /* dynamic AFE power control */ -+#define rA_AFEPwr2_Jaguar 0xc64 /* dynamic AFE power control */ -+#define rA_Rx_WaitCCA_Tx_CCKRFON_Jaguar 0xc68 -+#define rA_Tx_CCKBBON_OFDMRFON_Jaguar 0xc6c -+#define rA_Tx_OFDMBBON_Tx2Rx_Jaguar 0xc70 -+#define rA_Tx2Tx_RXCCK_Jaguar 0xc74 -+#define rA_Rx_OFDM_WaitRIFS_Jaguar 0xc78 -+#define rA_Rx2Rx_BT_Jaguar 0xc7c -+#define rA_sleep_nav_Jaguar 0xc80 -+#define rA_pmpd_Jaguar 0xc84 -+#define rB_AFEPwr1_Jaguar 0xe60 /* dynamic AFE power control */ -+#define rB_AFEPwr2_Jaguar 0xe64 /* dynamic AFE power control */ -+#define rB_Rx_WaitCCA_Tx_CCKRFON_Jaguar 0xe68 -+#define rB_Tx_CCKBBON_OFDMRFON_Jaguar 0xe6c -+#define rB_Tx_OFDMBBON_Tx2Rx_Jaguar 0xe70 -+#define rB_Tx2Tx_RXCCK_Jaguar 0xe74 -+#define rB_Rx_OFDM_WaitRIFS_Jaguar 0xe78 -+#define rB_Rx2Rx_BT_Jaguar 0xe7c -+#define rB_sleep_nav_Jaguar 0xe80 -+#define rB_pmpd_Jaguar 0xe84 -+ -+ -+/* YN: mask these registers temporaily -+ * #define rTx_Power_Before_IQK_A 0xe94 -+ * #define rTx_Power_After_IQK_A 0xe9c */ -+ -+/* #define rRx_Power_Before_IQK_A 0xea0 */ -+/* #define rRx_Power_Before_IQK_A_2 0xea4 */ -+/* #define rRx_Power_After_IQK_A 0xea8 */ -+/* #define rRx_Power_After_IQK_A_2 0xeac */ -+ -+/* #define rTx_Power_Before_IQK_B 0xeb4 */ -+/* #define rTx_Power_After_IQK_B 0xebc */ -+ -+/* #define rRx_Power_Before_IQK_B 0xec0 */ -+/* #define rRx_Power_Before_IQK_B_2 0xec4 */ -+/* #define rRx_Power_After_IQK_B 0xec8 */ -+/* #define rRx_Power_After_IQK_B_2 0xecc */ -+ -+ -+/* RSSI Dump */ -+#define rA_RSSIDump_Jaguar 0xBF0 -+#define rB_RSSIDump_Jaguar 0xBF1 -+#define rS1_RXevmDump_Jaguar 0xBF4 -+#define rS2_RXevmDump_Jaguar 0xBF5 -+#define rA_RXsnrDump_Jaguar 0xBF6 -+#define rB_RXsnrDump_Jaguar 0xBF7 -+#define rA_CfoShortDump_Jaguar 0xBF8 -+#define rB_CfoShortDump_Jaguar 0xBFA -+#define rA_CfoLongDump_Jaguar 0xBEC -+#define rB_CfoLongDump_Jaguar 0xBEE -+ -+ -+/* RF Register -+ * */ -+#define RF_AC_Jaguar 0x00 /* */ -+#define RF_RF_Top_Jaguar 0x07 /* */ -+#define RF_TXLOK_Jaguar 0x08 /* */ -+#define RF_TXAPK_Jaguar 0x0B -+#define RF_CHNLBW_Jaguar 0x18 /* RF channel and BW switch */ -+#define RF_RCK1_Jaguar 0x1c /* */ -+#define RF_RCK2_Jaguar 0x1d -+#define RF_RCK3_Jaguar 0x1e -+#define RF_ModeTableAddr 0x30 -+#define RF_ModeTableData0 0x31 -+#define RF_ModeTableData1 0x32 -+#define RF_TxLCTank_Jaguar 0x54 -+#define RF_APK_Jaguar 0x63 -+#define RF_LCK 0xB4 -+#define RF_WeLut_Jaguar 0xEF -+ -+#define bRF_CHNLBW_MOD_AG_Jaguar 0x70300 -+#define bRF_CHNLBW_BW 0xc00 -+ -+ -+/* -+ * RL6052 Register definition -+ * */ -+#define RF_AC 0x00 /* */ -+#define RF_IPA_A 0x0C /* */ -+#define RF_TXBIAS_A 0x0D -+#define RF_BS_PA_APSET_G9_G11 0x0E -+#define RF_MODE1 0x10 /* */ -+#define RF_MODE2 0x11 /* */ -+#define RF_CHNLBW 0x18 /* RF channel and BW switch */ -+#define RF_RCK_OS 0x30 /* RF TX PA control */ -+#define RF_TXPA_G1 0x31 /* RF TX PA control */ -+#define RF_TXPA_G2 0x32 /* RF TX PA control */ -+#define RF_TXPA_G3 0x33 /* RF TX PA control */ -+#define RF_0x52 0x52 -+#define RF_WE_LUT 0xEF -+ -+/* -+ * Bit Mask -+ * -+ * 1. Page1(0x100) */ -+#define bBBResetB 0x100 /* Useless now? */ -+#define bGlobalResetB 0x200 -+#define bOFDMTxStart 0x4 -+#define bCCKTxStart 0x8 -+#define bCRC32Debug 0x100 -+#define bPMACLoopback 0x10 -+#define bTxLSIG 0xffffff -+#define bOFDMTxRate 0xf -+#define bOFDMTxReserved 0x10 -+#define bOFDMTxLength 0x1ffe0 -+#define bOFDMTxParity 0x20000 -+#define bTxHTSIG1 0xffffff -+#define bTxHTMCSRate 0x7f -+#define bTxHTBW 0x80 -+#define bTxHTLength 0xffff00 -+#define bTxHTSIG2 0xffffff -+#define bTxHTSmoothing 0x1 -+#define bTxHTSounding 0x2 -+#define bTxHTReserved 0x4 -+#define bTxHTAggreation 0x8 -+#define bTxHTSTBC 0x30 -+#define bTxHTAdvanceCoding 0x40 -+#define bTxHTShortGI 0x80 -+#define bTxHTNumberHT_LTF 0x300 -+#define bTxHTCRC8 0x3fc00 -+#define bCounterReset 0x10000 -+#define bNumOfOFDMTx 0xffff -+#define bNumOfCCKTx 0xffff0000 -+#define bTxIdleInterval 0xffff -+#define bOFDMService 0xffff0000 -+#define bTxMACHeader 0xffffffff -+#define bTxDataInit 0xff -+#define bTxHTMode 0x100 -+#define bTxDataType 0x30000 -+#define bTxRandomSeed 0xffffffff -+#define bCCKTxPreamble 0x1 -+#define bCCKTxSFD 0xffff0000 -+#define bCCKTxSIG 0xff -+#define bCCKTxService 0xff00 -+#define bCCKLengthExt 0x8000 -+#define bCCKTxLength 0xffff0000 -+#define bCCKTxCRC16 0xffff -+#define bCCKTxStatus 0x1 -+#define bOFDMTxStatus 0x2 -+ -+ -+/* -+ * 1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF -+ * 1. Page1(0x100) -+ * */ -+#define rPMAC_Reset 0x100 -+#define rPMAC_TxStart 0x104 -+#define rPMAC_TxLegacySIG 0x108 -+#define rPMAC_TxHTSIG1 0x10c -+#define rPMAC_TxHTSIG2 0x110 -+#define rPMAC_PHYDebug 0x114 -+#define rPMAC_TxPacketNum 0x118 -+#define rPMAC_TxIdle 0x11c -+#define rPMAC_TxMACHeader0 0x120 -+#define rPMAC_TxMACHeader1 0x124 -+#define rPMAC_TxMACHeader2 0x128 -+#define rPMAC_TxMACHeader3 0x12c -+#define rPMAC_TxMACHeader4 0x130 -+#define rPMAC_TxMACHeader5 0x134 -+#define rPMAC_TxDataType 0x138 -+#define rPMAC_TxRandomSeed 0x13c -+#define rPMAC_CCKPLCPPreamble 0x140 -+#define rPMAC_CCKPLCPHeader 0x144 -+#define rPMAC_CCKCRC16 0x148 -+#define rPMAC_OFDMRxCRC32OK 0x170 -+#define rPMAC_OFDMRxCRC32Er 0x174 -+#define rPMAC_OFDMRxParityEr 0x178 -+#define rPMAC_OFDMRxCRC8Er 0x17c -+#define rPMAC_CCKCRxRC16Er 0x180 -+#define rPMAC_CCKCRxRC32Er 0x184 -+#define rPMAC_CCKCRxRC32OK 0x188 -+#define rPMAC_TxStatus 0x18c -+ -+/* -+ * 3. Page8(0x800) -+ * */ -+#define rFPGA0_RFMOD 0x800 /* RF mode & CCK TxSC */ /* RF BW Setting?? */ -+ -+#define rFPGA0_TxInfo 0x804 /* Status report?? */ -+#define rFPGA0_PSDFunction 0x808 -+#define rFPGA0_TxGainStage 0x80c /* Set TX PWR init gain? */ -+ -+#define rFPGA0_XA_HSSIParameter1 0x820 /* RF 3 wire register */ -+#define rFPGA0_XA_HSSIParameter2 0x824 -+#define rFPGA0_XB_HSSIParameter1 0x828 -+#define rFPGA0_XB_HSSIParameter2 0x82c -+ -+#define rFPGA0_XA_LSSIParameter 0x840 -+#define rFPGA0_XB_LSSIParameter 0x844 -+ -+#define rFPGA0_XAB_SwitchControl 0x858 /* RF Channel switch */ -+#define rFPGA0_XCD_SwitchControl 0x85c -+ -+#define rFPGA0_XAB_RFParameter 0x878 /* RF Parameter */ -+#define rFPGA0_XCD_RFParameter 0x87c -+ -+#define rFPGA0_AnalogParameter1 0x880 /* Crystal cap setting RF-R/W protection for parameter4?? */ -+#define rFPGA0_AnalogParameter2 0x884 -+#define rFPGA0_AnalogParameter3 0x888 -+#define rFPGA0_AdDaClockEn 0x888 /* enable ad/da clock1 for dual-phy */ -+#define rFPGA0_AnalogParameter4 0x88c -+ -+#define rFPGA0_XA_LSSIReadBack 0x8a0 /* Tranceiver LSSI Readback */ -+#define rFPGA0_XB_LSSIReadBack 0x8a4 -+#define rFPGA0_XC_LSSIReadBack 0x8a8 -+#define rFPGA0_XD_LSSIReadBack 0x8ac -+ -+#define rFPGA0_XCD_RFPara 0x8b4 -+#define rFPGA0_PSDReport 0x8b4 /* Useless now */ -+#define TransceiverA_HSPI_Readback 0x8b8 /* Transceiver A HSPI Readback */ -+#define TransceiverB_HSPI_Readback 0x8bc /* Transceiver B HSPI Readback */ -+#define rFPGA0_XAB_RFInterfaceRB 0x8e0 /* Useless now */ /* RF Interface Readback Value */ -+#define rFPGA0_XCD_RFInterfaceRB 0x8e4 /* Useless now */ -+ -+/* -+ * 4. Page9(0x900) -+ * */ -+#define rFPGA1_RFMOD 0x900 /* RF mode & OFDM TxSC */ /* RF BW Setting?? */ -+#define REG_BB_TX_PATH_SEL_1_8814A 0x93c -+#define REG_BB_TX_PATH_SEL_2_8814A 0x940 -+#define rFPGA1_TxBlock 0x904 /* Useless now */ -+#define rFPGA1_DebugSelect 0x908 /* Useless now */ -+#define rFPGA1_TxInfo 0x90c /* Useless now */ /* Status report?? */ -+/*Page 19 for TxBF*/ -+#define REG_BB_TXBF_ANT_SET_BF1_8814A 0x19ac -+#define REG_BB_TXBF_ANT_SET_BF0_8814A 0x19b4 -+/* -+ * PageA(0xA00) -+ * */ -+#define rCCK0_System 0xa00 -+#define rCCK0_AFESetting 0xa04 /* Disable init gain now */ /* Select RX path by RSSI */ -+#define rCCK0_DSPParameter2 0xa1c /* SQ threshold */ -+#define rCCK0_TxFilter1 0xa20 -+#define rCCK0_TxFilter2 0xa24 -+#define rCCK0_DebugPort 0xa28 /* debug port and Tx filter3 */ -+#define rCCK0_FalseAlarmReport 0xa2c /* 0xa2d useless now 0xa30-a4f channel report */ -+ -+/* -+ * PageB(0xB00) -+ * */ -+#define rPdp_AntA 0xb00 -+#define rPdp_AntA_4 0xb04 -+#define rConfig_Pmpd_AntA 0xb28 -+#define rConfig_AntA 0xb68 -+#define rConfig_AntB 0xb6c -+#define rPdp_AntB 0xb70 -+#define rPdp_AntB_4 0xb74 -+#define rConfig_Pmpd_AntB 0xb98 -+#define rAPK 0xbd8 -+ -+/* -+ * 6. PageC(0xC00) -+ * */ -+#define rOFDM0_LSTF 0xc00 -+ -+#define rOFDM0_TRxPathEnable 0xc04 -+#define rOFDM0_TRMuxPar 0xc08 -+#define rOFDM0_TRSWIsolation 0xc0c -+ -+#define rOFDM0_XARxAFE 0xc10 /* RxIQ DC offset, Rx digital filter, DC notch filter */ -+#define rOFDM0_XARxIQImbalance 0xc14 /* RxIQ imblance matrix */ -+#define rOFDM0_XBRxAFE 0xc18 -+#define rOFDM0_XBRxIQImbalance 0xc1c -+#define rOFDM0_XCRxAFE 0xc20 -+#define rOFDM0_XCRxIQImbalance 0xc24 -+#define rOFDM0_XDRxAFE 0xc28 -+#define rOFDM0_XDRxIQImbalance 0xc2c -+ -+#define rOFDM0_RxDetector1 0xc30 /* PD, BW & SBD */ /* DM tune init gain */ -+#define rOFDM0_RxDetector2 0xc34 /* SBD & Fame Sync. */ -+#define rOFDM0_RxDetector3 0xc38 /* Frame Sync. */ -+#define rOFDM0_RxDetector4 0xc3c /* PD, SBD, Frame Sync & Short-GI */ -+ -+#define rOFDM0_RxDSP 0xc40 /* Rx Sync Path */ -+#define rOFDM0_CFOandDAGC 0xc44 /* CFO & DAGC */ -+#define rOFDM0_CCADropThreshold 0xc48 /* CCA Drop threshold */ -+#define rOFDM0_ECCAThreshold 0xc4c /* energy CCA */ -+ -+#define rOFDM0_XAAGCCore1 0xc50 /* DIG */ -+#define rOFDM0_XAAGCCore2 0xc54 -+#define rOFDM0_XBAGCCore1 0xc58 -+#define rOFDM0_XBAGCCore2 0xc5c -+#define rOFDM0_XCAGCCore1 0xc60 -+#define rOFDM0_XCAGCCore2 0xc64 -+#define rOFDM0_XDAGCCore1 0xc68 -+#define rOFDM0_XDAGCCore2 0xc6c -+ -+#define rOFDM0_AGCParameter1 0xc70 -+#define rOFDM0_AGCParameter2 0xc74 -+#define rOFDM0_AGCRSSITable 0xc78 -+#define rOFDM0_HTSTFAGC 0xc7c -+ -+#define rOFDM0_XATxIQImbalance 0xc80 /* TX PWR TRACK and DIG */ -+#define rOFDM0_XATxAFE 0xc84 -+#define rOFDM0_XBTxIQImbalance 0xc88 -+#define rOFDM0_XBTxAFE 0xc8c -+#define rOFDM0_XCTxIQImbalance 0xc90 -+#define rOFDM0_XCTxAFE 0xc94 -+#define rOFDM0_XDTxIQImbalance 0xc98 -+#define rOFDM0_XDTxAFE 0xc9c -+ -+#define rOFDM0_RxIQExtAnta 0xca0 -+#define rOFDM0_TxCoeff1 0xca4 -+#define rOFDM0_TxCoeff2 0xca8 -+#define rOFDM0_TxCoeff3 0xcac -+#define rOFDM0_TxCoeff4 0xcb0 -+#define rOFDM0_TxCoeff5 0xcb4 -+#define rOFDM0_TxCoeff6 0xcb8 -+#define rOFDM0_RxHPParameter 0xce0 -+#define rOFDM0_TxPseudoNoiseWgt 0xce4 -+#define rOFDM0_FrameSync 0xcf0 -+#define rOFDM0_DFSReport 0xcf4 -+ -+/* -+ * 7. PageD(0xD00) -+ * */ -+#define rOFDM1_LSTF 0xd00 -+#define rOFDM1_TRxPathEnable 0xd04 -+ -+/* -+ * 8. PageE(0xE00) -+ * */ -+#define rTxAGC_A_Rate18_06 0xe00 -+#define rTxAGC_A_Rate54_24 0xe04 -+#define rTxAGC_A_CCK1_Mcs32 0xe08 -+#define rTxAGC_A_Mcs03_Mcs00 0xe10 -+#define rTxAGC_A_Mcs07_Mcs04 0xe14 -+#define rTxAGC_A_Mcs11_Mcs08 0xe18 -+#define rTxAGC_A_Mcs15_Mcs12 0xe1c -+ -+#define rTxAGC_B_Rate18_06 0x830 -+#define rTxAGC_B_Rate54_24 0x834 -+#define rTxAGC_B_CCK1_55_Mcs32 0x838 -+#define rTxAGC_B_Mcs03_Mcs00 0x83c -+#define rTxAGC_B_Mcs07_Mcs04 0x848 -+#define rTxAGC_B_Mcs11_Mcs08 0x84c -+#define rTxAGC_B_Mcs15_Mcs12 0x868 -+#define rTxAGC_B_CCK11_A_CCK2_11 0x86c -+ -+#define rFPGA0_IQK 0xe28 -+#define rTx_IQK_Tone_A 0xe30 -+#define rRx_IQK_Tone_A 0xe34 -+#define rTx_IQK_PI_A 0xe38 -+#define rRx_IQK_PI_A 0xe3c -+ -+#define rTx_IQK 0xe40 -+#define rRx_IQK 0xe44 -+#define rIQK_AGC_Pts 0xe48 -+#define rIQK_AGC_Rsp 0xe4c -+#define rTx_IQK_Tone_B 0xe50 -+#define rRx_IQK_Tone_B 0xe54 -+#define rTx_IQK_PI_B 0xe58 -+#define rRx_IQK_PI_B 0xe5c -+#define rIQK_AGC_Cont 0xe60 -+ -+#define rBlue_Tooth 0xe6c -+#define rRx_Wait_CCA 0xe70 -+#define rTx_CCK_RFON 0xe74 -+#define rTx_CCK_BBON 0xe78 -+#define rTx_OFDM_RFON 0xe7c -+#define rTx_OFDM_BBON 0xe80 -+#define rTx_To_Rx 0xe84 -+#define rTx_To_Tx 0xe88 -+#define rRx_CCK 0xe8c -+ -+#define rTx_Power_Before_IQK_A 0xe94 -+#define rTx_Power_After_IQK_A 0xe9c -+ -+#define rRx_Power_Before_IQK_A 0xea0 -+#define rRx_Power_Before_IQK_A_2 0xea4 -+#define rRx_Power_After_IQK_A 0xea8 -+#define rRx_Power_After_IQK_A_2 0xeac -+ -+#define rTx_Power_Before_IQK_B 0xeb4 -+#define rTx_Power_After_IQK_B 0xebc -+ -+#define rRx_Power_Before_IQK_B 0xec0 -+#define rRx_Power_Before_IQK_B_2 0xec4 -+#define rRx_Power_After_IQK_B 0xec8 -+#define rRx_Power_After_IQK_B_2 0xecc -+ -+#define rRx_OFDM 0xed0 -+#define rRx_Wait_RIFS 0xed4 -+#define rRx_TO_Rx 0xed8 -+#define rStandby 0xedc -+#define rSleep 0xee0 -+#define rPMPD_ANAEN 0xeec -+ -+ -+/* 2. Page8(0x800) */ -+#define bRFMOD 0x1 /* Reg 0x800 rFPGA0_RFMOD */ -+#define bJapanMode 0x2 -+#define bCCKTxSC 0x30 -+#define bCCKEn 0x1000000 -+#define bOFDMEn 0x2000000 -+#define bXBTxAGC 0xf00 /* Reg 80c rFPGA0_TxGainStage */ -+#define bXCTxAGC 0xf000 -+#define bXDTxAGC 0xf0000 -+ -+/* 4. PageA(0xA00) */ -+#define bCCKBBMode 0x3 /* Useless */ -+#define bCCKTxPowerSaving 0x80 -+#define bCCKRxPowerSaving 0x40 -+ -+#define bCCKSideBand 0x10 /* Reg 0xa00 rCCK0_System 20/40 switch */ -+ -+#define bCCKScramble 0x8 /* Useless */ -+#define bCCKAntDiversity 0x8000 -+#define bCCKCarrierRecovery 0x4000 -+#define bCCKTxRate 0x3000 -+#define bCCKDCCancel 0x0800 -+#define bCCKISICancel 0x0400 -+#define bCCKMatchFilter 0x0200 -+#define bCCKEqualizer 0x0100 -+#define bCCKPreambleDetect 0x800000 -+#define bCCKFastFalseCCA 0x400000 -+#define bCCKChEstStart 0x300000 -+#define bCCKCCACount 0x080000 -+#define bCCKcs_lim 0x070000 -+#define bCCKBistMode 0x80000000 -+#define bCCKCCAMask 0x40000000 -+#define bCCKTxDACPhase 0x4 -+#define bCCKRxADCPhase 0x20000000 /* r_rx_clk */ -+#define bCCKr_cp_mode0 0x0100 -+#define bCCKTxDCOffset 0xf0 -+#define bCCKRxDCOffset 0xf -+#define bCCKCCAMode 0xc000 -+#define bCCKFalseCS_lim 0x3f00 -+#define bCCKCS_ratio 0xc00000 -+#define bCCKCorgBit_sel 0x300000 -+#define bCCKPD_lim 0x0f0000 -+#define bCCKNewCCA 0x80000000 -+#define bCCKRxHPofIG 0x8000 -+#define bCCKRxIG 0x7f00 -+#define bCCKLNAPolarity 0x800000 -+#define bCCKRx1stGain 0x7f0000 -+#define bCCKRFExtend 0x20000000 /* CCK Rx Iinital gain polarity */ -+#define bCCKRxAGCSatLevel 0x1f000000 -+#define bCCKRxAGCSatCount 0xe0 -+#define bCCKRxRFSettle 0x1f /* AGCsamp_dly */ -+#define bCCKFixedRxAGC 0x8000 -+/* #define bCCKRxAGCFormat 0x4000 */ /* remove to HSSI register 0x824 */ -+#define bCCKAntennaPolarity 0x2000 -+#define bCCKTxFilterType 0x0c00 -+#define bCCKRxAGCReportType 0x0300 -+#define bCCKRxDAGCEn 0x80000000 -+#define bCCKRxDAGCPeriod 0x20000000 -+#define bCCKRxDAGCSatLevel 0x1f000000 -+#define bCCKTimingRecovery 0x800000 -+#define bCCKTxC0 0x3f0000 -+#define bCCKTxC1 0x3f000000 -+#define bCCKTxC2 0x3f -+#define bCCKTxC3 0x3f00 -+#define bCCKTxC4 0x3f0000 -+#define bCCKTxC5 0x3f000000 -+#define bCCKTxC6 0x3f -+#define bCCKTxC7 0x3f00 -+#define bCCKDebugPort 0xff0000 -+#define bCCKDACDebug 0x0f000000 -+#define bCCKFalseAlarmEnable 0x8000 -+#define bCCKFalseAlarmRead 0x4000 -+#define bCCKTRSSI 0x7f -+#define bCCKRxAGCReport 0xfe -+#define bCCKRxReport_AntSel 0x80000000 -+#define bCCKRxReport_MFOff 0x40000000 -+#define bCCKRxRxReport_SQLoss 0x20000000 -+#define bCCKRxReport_Pktloss 0x10000000 -+#define bCCKRxReport_Lockedbit 0x08000000 -+#define bCCKRxReport_RateError 0x04000000 -+#define bCCKRxReport_RxRate 0x03000000 -+#define bCCKRxFACounterLower 0xff -+#define bCCKRxFACounterUpper 0xff000000 -+#define bCCKRxHPAGCStart 0xe000 -+#define bCCKRxHPAGCFinal 0x1c00 -+#define bCCKRxFalseAlarmEnable 0x8000 -+#define bCCKFACounterFreeze 0x4000 -+#define bCCKTxPathSel 0x10000000 -+#define bCCKDefaultRxPath 0xc000000 -+#define bCCKOptionRxPath 0x3000000 -+ -+#define RF_T_METER_88E 0x42 -+ -+/* 6. PageE(0xE00) */ -+#define bSTBCEn 0x4 /* Useless */ -+#define bAntennaMapping 0x10 -+#define bNss 0x20 -+#define bCFOAntSumD 0x200 -+#define bPHYCounterReset 0x8000000 -+#define bCFOReportGet 0x4000000 -+#define bOFDMContinueTx 0x10000000 -+#define bOFDMSingleCarrier 0x20000000 -+#define bOFDMSingleTone 0x40000000 -+ -+ -+/* -+ * Other Definition -+ * */ -+ -+#define bEnable 0x1 /* Useless */ -+#define bDisable 0x0 -+ -+/* byte endable for srwrite */ -+#define bByte0 0x1 /* Useless */ -+#define bByte1 0x2 -+#define bByte2 0x4 -+#define bByte3 0x8 -+#define bWord0 0x3 -+#define bWord1 0xc -+#define bDWord 0xf -+ -+/* for PutRegsetting & GetRegSetting BitMask */ -+#define bMaskByte0 0xff /* Reg 0xc50 rOFDM0_XAAGCCore~0xC6f */ -+#define bMaskByte1 0xff00 -+#define bMaskByte2 0xff0000 -+#define bMaskByte3 0xff000000 -+#define bMaskHWord 0xffff0000 -+#define bMaskLWord 0x0000ffff -+#define bMaskDWord 0xffffffff -+#define bMaskH3Bytes 0xffffff00 -+#define bMask12Bits 0xfff -+#define bMaskH4Bits 0xf0000000 -+#define bMaskOFDM_D 0xffc00000 -+#define bMaskCCK 0x3f3f3f3f -+#define bMask7bits 0x7f -+#define bMaskByte2HighNibble 0x00f00000 -+#define bMaskByte3LowNibble 0x0f000000 -+#define bMaskL3Bytes 0x00ffffff -+ -+/*--------------------------Define Parameters-------------------------------*/ -+ -+ -+#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/Hal8814PwrSeq.h linux-5.8/3rdparty/rtl8812au/include/Hal8814PwrSeq.h -new file mode 100644 -index 000000000..020ddbcba ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/Hal8814PwrSeq.h -@@ -0,0 +1,231 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+ -+ -+#ifndef __HAL8814PWRSEQ_H__ -+#define __HAL8814PWRSEQ_H__ -+ -+#include "HalPwrSeqCmd.h" -+ -+/* -+ Check document WB-110628-DZ-RTL8195 (Jaguar) Power Architecture-R04.pdf -+ There are 6 HW Power States: -+ 0: POFF--Power Off -+ 1: PDN--Power Down -+ 2: CARDEMU--Card Emulation -+ 3: ACT--Active Mode -+ 4: LPS--Low Power State -+ 5: SUS--Suspend -+ -+ The transision from different states are defined below -+ TRANS_CARDEMU_TO_ACT -+ TRANS_ACT_TO_CARDEMU -+ TRANS_CARDEMU_TO_SUS -+ TRANS_SUS_TO_CARDEMU -+ TRANS_CARDEMU_TO_PDN -+ TRANS_ACT_TO_LPS -+ TRANS_LPS_TO_ACT -+ -+ TRANS_END -+*/ -+#define RTL8814A_TRANS_CARDEMU_TO_ACT_STEPS 16 -+#define RTL8814A_TRANS_ACT_TO_CARDEMU_STEPS 20 -+#define RTL8814A_TRANS_CARDEMU_TO_SUS_STEPS 17 -+#define RTL8814A_TRANS_SUS_TO_CARDEMU_STEPS 15 -+#define RTL8814A_TRANS_CARDEMU_TO_PDN_STEPS 17 -+#define RTL8814A_TRANS_PDN_TO_CARDEMU_STEPS 16 -+#define RTL8814A_TRANS_ACT_TO_LPS_STEPS 20 -+#define RTL8814A_TRANS_LPS_TO_ACT_STEPS 15 -+#define RTL8814A_TRANS_END_STEPS 1 -+ -+ -+#define RTL8814A_TRANS_CARDEMU_TO_ACT \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, 0},/* disable SW LPS 0x04[10]=0*/ \ -+ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT1, BIT1},/* wait till 0x04[17] = 1 power ready*/ \ -+ {0x002B, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0}, /* ??0x28[24]=1, enable pll phase select*/ \ -+ {0x0015, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, (BIT3 | BIT2 | BIT1), (BIT3 | BIT2 | BIT1)},/* 0x14[11:9]=3'b111, OCP current threshold = 1.5A */ \ -+ {0x002D, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x0E, 0x08},/* 0x2C[11:9]=3'b100, select lpf R3 */ \ -+ {0x002D, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x70, 0x50},/* 0x2C[14:12]=3'b101, select lpf Rs*/ \ -+ {0x007B, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6, BIT6},/* 0x78[30]=1'b1, SDM order select*/ \ -+ /*{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0}, */ /* disable HWPDN 0x04[15]=0*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3, 0},/* disable WL suspend*/ \ -+ {0x00F0, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0},/* */ \ -+ {0x0081, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x30, 0x20},/* */ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/* polling until return 0*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT0, 0},/**/ -+ -+#define RTL8814A_TRANS_ACT_TO_CARDEMU \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ {0x0c00, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x04}, /* 0xc00[7:0] = 4 turn off 3-wire */ \ -+ {0x0e00, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x04}, /* 0xe00[7:0] = 4 turn off 3-wire */ \ -+ {0x0002, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0}, /* 0x2[0] = 0 RESET BB, CLOSE RF */ \ -+ {0x0002, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US}, /*Delay 1us*/ \ -+ {0x0002, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0}, /* Whole BB is reset*/ \ -+ {0x1002, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0}, /* 0x2[0] = 0 RESET BB, CLOSE RF */ \ -+ {0x0002, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US}, /*Delay 1us*/ \ -+ {0x1002, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0}, /* Whole BB is reset*/ \ -+ {0x001F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}, /*0x1F[7:0] = 0 turn off RF*/ \ -+ /*{0x004E, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0},*/ /*0x4C[23] = 0x4E[7] = 0, switch DPDT_SEL_P output from register 0x65[2] */ \ -+ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x28}, /* 0x07[7:0] = 0x28 sps pwm mode 0x2a for BT coex*/ \ -+ {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x02, 0}, /*0x8[1] = 0 ANA clk = 500k */ \ -+ /*{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0 | BIT1, 0},*/ /* 0x02[1:0] = 0 reset BB */ \ -+ {0x0066, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0}, /*0x66[7]=0, disable ckreq for gpio7 output SUS */ \ -+ {0x0041, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*0x41[4]=0, disable sic for gpio7 output SUS */ \ -+ {0x0042, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0}, /*0x42[1]=0, disable ckout for gpio7 output SUS */ \ -+ {0x004e, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, BIT5}, /*0x4E[5]=1, disable LED2 for gpio7 output SUS */ \ -+ {0x0041, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0}, /*0x41[0]=0, disable uart for gpio7 output SUS */ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1}, /*0x04[9] = 1 turn off MAC by HW state machine*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT1, 0}, /*wait till 0x04[9] = 0 polling until return 0 to disable*/ -+ -+#define RTL8814A_TRANS_CARDEMU_TO_SUS \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ {0x0061, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x0F, 0x0c},\ -+ {0x0061, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x0F, 0x0E},\ -+ {0x0062, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x0F, 0x07},/* gpio11 input mode, gpio10~8 output mode */ \ -+ {0x0045, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00},/* gpio 0~7 output same value as input ?? */ \ -+ {0x0046, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xff},/* gpio0~7 output mode */ \ -+ {0x0047, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/* 0x47[7:0] = 00 gpio mode */ \ -+ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/* suspend option all off */ \ -+ {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, BIT5},/*0x14[13] = 1 turn on ZCD */ \ -+ {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6, BIT6},/* 0x14[14] =1 trun on ZCD */ \ -+ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, BIT4},/*0x23[4] = 1 hpon LDO sleep mode */ \ -+ {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0},/*0x8[1] = 0 ANA clk = 500k */ \ -+ {0x0091, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xA0, 0xA0}, /* 0x91[7]=1 0x91[5]=1 , disable sps, ldo sleep mode */ \ -+ {0x0070, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3, BIT3}, /* 0x70[3]=1 enable mainbias polling */ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3, BIT3}, /*0x04[11] = 1 enable WL suspend */ -+ -+#define RTL8814A_TRANS_SUS_TO_CARDEMU \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3, 0}, /*0x04[11] = 0 enable WL suspend*/ \ -+ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x10, 0},/*0x23[4] = 0 hpon LDO sleep mode leave */ \ -+ {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6, 0},/* 0x14[14] =0 trun off ZCD */ \ -+ {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, 0},/*0x14[13] = 0 turn off ZCD */ \ -+ {0x0046, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00},/* gpio0~7 input mode */ \ -+ {0x0062, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00},/* gpio11 input mode, gpio10~8 input mode */ -+ -+#define RTL8814A_TRANS_CARDEMU_TO_CARDDIS \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ /**{0x0194, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0}, //0x194[0]=0 , disable 32K clock*/ \ -+ /**{0x0093, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x94}, //0x93 = 0x94 , 90[30] =0 enable 500k ANA clock .switch clock from 12M to 500K , 90 [26] =0 disable EEprom loader clock*/ \ -+ {0x0003, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, 0}, /*0x03[2] = 0, reset 3081*/ \ -+ {0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x01}, /*0x80 = 05h if reload fw, fill the default value of host_CPU handshake field*/ \ -+ {0x0081, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x30}, /*0x80 = 05h if reload fw, fill the default value of host_CPU handshake field*/ \ -+ /*{0x0042, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xF0, 0xcc},*/ \ -+ /*{0x0042, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xF0, 0xEC},*/ \ -+ /*{0x0043, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x07},*/ /* gpio11 input mode, gpio10~8 output mode */ \ -+ {0x0045, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00},/* gpio 0~7 output same value as input ?? */ \ -+ {0x0046, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xff},/* gpio0~7 output mode */ \ -+ {0x0047, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/* 0x47[7:0] = 00 gpio mode */ \ -+ {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6, BIT6},/* 0x15[6] =1 trun on ZCD output */ \ -+ {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, BIT5},/*0x15[5] = 1 turn on ZCD */ \ -+ {0x0012, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6, 0},/*0x12[6] = 0 force PFM mode */ \ -+ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, BIT4},/*0x23[4] = 1 hpon LDO sleep mode */ \ -+ {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0},/*0x8[1] = 0 ANA clk = 500k */ \ -+ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07 = 0x20 , SOP option to disable BG/MB*/ \ -+ {0x001f, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0}, /* 0x01f[1]=0 , disable RFC_0 control REG_RF_CTRL_8814A */ \ -+ {0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0}, /* 0x020[1]=0 , disable RFC_1 control REG_RF_CTRL_8814A */ \ -+ {0x0021, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0}, /* 0x021[1]=0 , disable RFC_2 control REG_RF_CTRL_8814A */ \ -+ {0x0076, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0}, /* 0x076[1]=0 , disable RFC_3 control REG_OPT_CTRL_8814A +2 */ \ -+ {0x0091, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xA0, 0xA0}, /* 0x91[7]=1 0x91[5]=1 , disable sps, ldo sleep mode */ \ -+ {0x0070, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3, BIT3}, /* 0x70[3]=1 enable mainbias polling */ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3, BIT3}, /*0x04[11] = 1 enable WL suspend*/ -+ -+#define RTL8814A_TRANS_CARDDIS_TO_CARDEMU \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ {0x0012, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6, BIT6},/*0x12[6] = 1 force PWM mode */ \ -+ {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, 0},/*0x15[5] = 0 turn off ZCD */ \ -+ {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6, 0},/* 0x15[6] =0 trun off ZCD output */ \ -+ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0},/*0x23[4] = 0 hpon LDO leave sleep mode */ \ -+ {0x0046, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00},/* gpio0~7 input mode */ \ -+ {0x0062, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00}, /* gpio11 input mode, gpio10~8 input mode */ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, 0}, /*0x04[10] = 0, enable SW LPS PCIE only*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3, 0}, /*0x04[11] = 0, enable WL suspend*/ \ -+ /*{0x0003, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, BIT2},*/ /*0x03[2] = 1, enable 3081*/ \ -+ {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/*PCIe DMA start*/ \ -+ {0x0071, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, 0},/*0x70[10] = 0, CPHY_MBIAS_EN disable*/ -+ -+ -+#define RTL8814A_TRANS_CARDEMU_TO_PDN \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, BIT7},/* 0x04[15] = 1*/ -+ -+#define RTL8814A_TRANS_PDN_TO_CARDEMU \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0},/* 0x04[15] = 0*/ -+ -+#define RTL8814A_TRANS_ACT_TO_LPS \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF},/*PCIe DMA stop*/ \ -+ {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x7F},/*Tx Pause*/ \ -+ {0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ -+ {0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ -+ {0x05FA, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ -+ {0x05FB, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ -+ {0x0c00, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x04}, /* 0xc00[7:0] = 4 turn off 3-wire */ \ -+ {0x0e00, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x04}, /* 0xe00[7:0] = 4 turn off 3-wire */ \ -+ {0x0002, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0},/*CCK and OFDM are disabled, and clock are gated, and RF closed*/ \ -+ {0x0002, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US},/*Delay 1us*/ \ -+ {0x0002, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0}, /* Whole BB is reset*/ \ -+ {0x1002, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0},/*CCK and OFDM are disabled, and clock are gated, and RF closed*/ \ -+ {0x0002, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US},/*Delay 1us*/ \ -+ {0x1002, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0}, /* Whole BB is reset*/ \ -+ {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x03},/*Reset MAC TRX*/ \ -+ {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0},/*check if removed later*/ \ -+ {0x05F1, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/*Respond TxOK to scheduler*/ -+ -+ -+#define RTL8814A_TRANS_LPS_TO_ACT \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ {0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, 0xFF, 0x84}, /*SDIO RPWM*/ \ -+ {0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*USB RPWM*/ \ -+ {0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*PCIe RPWM*/ \ -+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS}, /* Delay*/ \ -+ {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*. 0x08[4] = 0 switch TSF to 40M*/ \ -+ {0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT7, 0}, /* Polling 0x109[7]=0 TSF in 40M*/ \ -+ /*{0x0029, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6 | BIT7, 0}, */ /*. ??0x29[7:6] = 2b'00 enable BB clock*/ \ -+ {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1}, /*. 0x101[1] = 1*/ \ -+ {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF}, /*. 0x100[7:0] = 0xFF enable WMAC TRX*/ \ -+ {0x0002, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1 | BIT0, BIT1 | BIT0}, /*. 0x02[1:0] = 2b'11 enable BB macro*/ \ -+ {0x1002, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1 | BIT0, BIT1 | BIT0}, /*. 0x1002[1:0] = 2b'11 enable BB macro*/ \ -+ {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}, /*. 0x522 = 0*/ -+ -+#define RTL8814A_TRANS_END \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ {0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, 0, PWR_CMD_END, 0, 0}, -+ -+ -+extern WLAN_PWR_CFG rtl8814A_power_on_flow[RTL8814A_TRANS_CARDEMU_TO_ACT_STEPS + RTL8814A_TRANS_END_STEPS]; -+extern WLAN_PWR_CFG rtl8814A_radio_off_flow[RTL8814A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8814A_TRANS_END_STEPS]; -+extern WLAN_PWR_CFG rtl8814A_card_disable_flow[RTL8814A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8814A_TRANS_CARDEMU_TO_PDN_STEPS + RTL8814A_TRANS_END_STEPS]; -+extern WLAN_PWR_CFG rtl8814A_card_enable_flow[RTL8814A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8814A_TRANS_CARDEMU_TO_PDN_STEPS + RTL8814A_TRANS_END_STEPS]; -+extern WLAN_PWR_CFG rtl8814A_suspend_flow[RTL8814A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8814A_TRANS_CARDEMU_TO_SUS_STEPS + RTL8814A_TRANS_END_STEPS]; -+extern WLAN_PWR_CFG rtl8814A_resume_flow[RTL8814A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8814A_TRANS_CARDEMU_TO_SUS_STEPS + RTL8814A_TRANS_END_STEPS]; -+extern WLAN_PWR_CFG rtl8814A_hwpdn_flow[RTL8814A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8814A_TRANS_CARDEMU_TO_PDN_STEPS + RTL8814A_TRANS_END_STEPS]; -+extern WLAN_PWR_CFG rtl8814A_enter_lps_flow[RTL8814A_TRANS_ACT_TO_LPS_STEPS + RTL8814A_TRANS_END_STEPS]; -+extern WLAN_PWR_CFG rtl8814A_leave_lps_flow[RTL8814A_TRANS_LPS_TO_ACT_STEPS + RTL8814A_TRANS_END_STEPS]; -+ -+#endif /* __HAL8814PWRSEQ_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/Hal8821APwrSeq.h linux-5.8/3rdparty/rtl8812au/include/Hal8821APwrSeq.h -new file mode 100644 -index 000000000..568b8e5fc ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/Hal8821APwrSeq.h -@@ -0,0 +1,200 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2016 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+#ifndef REALTEK_POWER_SEQUENCE_8821 -+#define REALTEK_POWER_SEQUENCE_8821 -+ -+#include "HalPwrSeqCmd.h" -+ -+/* -+ Check document WM-20130516-JackieLau-RTL8821A_Power_Architecture-R10.vsd -+ There are 6 HW Power States: -+ 0: POFF--Power Off -+ 1: PDN--Power Down -+ 2: CARDEMU--Card Emulation -+ 3: ACT--Active Mode -+ 4: LPS--Low Power State -+ 5: SUS--Suspend -+ -+ The transision from different states are defined below -+ TRANS_CARDEMU_TO_ACT -+ TRANS_ACT_TO_CARDEMU -+ TRANS_CARDEMU_TO_SUS -+ TRANS_SUS_TO_CARDEMU -+ TRANS_CARDEMU_TO_PDN -+ TRANS_ACT_TO_LPS -+ TRANS_LPS_TO_ACT -+ -+ TRANS_END -+*/ -+#define RTL8821A_TRANS_CARDEMU_TO_ACT_STEPS 25 -+#define RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS 15 -+#define RTL8821A_TRANS_CARDEMU_TO_SUS_STEPS 15 -+#define RTL8821A_TRANS_SUS_TO_CARDEMU_STEPS 15 -+#define RTL8821A_TRANS_CARDDIS_TO_CARDEMU_STEPS 15 -+#define RTL8821A_TRANS_CARDEMU_TO_PDN_STEPS 15 -+#define RTL8821A_TRANS_PDN_TO_CARDEMU_STEPS 15 -+#define RTL8821A_TRANS_ACT_TO_LPS_STEPS 15 -+#define RTL8821A_TRANS_LPS_TO_ACT_STEPS 15 -+#define RTL8821A_TRANS_END_STEPS 1 -+ -+ -+#define RTL8821A_TRANS_CARDEMU_TO_ACT \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ {0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0}, /*0x20[0] = 1b'1 enable LDOA12 MACRO block for all interface*/ \ -+ {0x0067, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*0x67[0] = 0 to disable BT_GPS_SEL pins*/ \ -+ {0x0001, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 1, PWRSEQ_DELAY_MS},/*Delay 1ms*/ \ -+ {0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, 0}, /*0x00[5] = 1b'0 release analog Ips to digital ,1:isolation*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, (BIT4 | BIT3 | BIT2), 0},/* disable SW LPS 0x04[10]=0 and WLSUS_EN 0x04[12:11]=0*/ \ -+ {0x0075, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0 , BIT0},/* Disable USB suspend */ \ -+ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT1, BIT1},/* wait till 0x04[17] = 1 power ready*/ \ -+ {0x0075, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0 , 0},/* Enable USB suspend */ \ -+ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/* release WLON reset 0x04[16]=1*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0},/* disable HWPDN 0x04[15]=0*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, (BIT4 | BIT3), 0},/* disable WL suspend*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/* polling until return 0*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT0, 0},/**/ \ -+ {0x004F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/*0x4C[24] = 0x4F[0] = 1, switch DPDT_SEL_P output from WL BB */\ -+ {0x0067, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, (BIT5 | BIT4), (BIT5 | BIT4)},/*0x66[13] = 0x67[5] = 1, switch for PAPE_G/PAPE_A from WL BB ; 0x66[12] = 0x67[4] = 1, switch LNAON from WL BB */\ -+ {0x0025, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6, 0},/*anapar_mac<118> , 0x25[6]=0 by wlan single function*/\ -+ {0x0049, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1},/*Enable falling edge triggering interrupt*/\ -+ {0x0063, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1},/*Enable GPIO9 interrupt mode*/\ -+ {0x0062, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0},/*Enable GPIO9 input mode*/\ -+ {0x0058, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/*Enable HSISR GPIO[C:0] interrupt*/\ -+ {0x005A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1},/*Enable HSISR GPIO9 interrupt*/\ -+ {0x007A, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x3A},/*0x7A = 0x3A start BT*/\ -+ {0x002E, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF , 0x82 },/* 0x2C[23:12]=0x820 ; XTAL trim */ \ -+ {0x0010, PWR_CUT_A_MSK , PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6 , BIT6 },/* 0x10[6]=1 ; MP·s¼W¹ï©ó0x2Cªº±±¨îÅv¡A¶·§â0x10[6]³]¬°1¤~¯àÅýWLAN±±¨î */ \ -+ -+ -+#define RTL8821A_TRANS_ACT_TO_CARDEMU \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ {0x001F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/*0x1F[7:0] = 0 turn off RF*/ \ -+ {0x004F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0},/*0x4C[24] = 0x4F[0] = 0, switch DPDT_SEL_P output from register 0x65[2] */\ -+ {0x0049, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0},/*Enable rising edge triggering interrupt*/ \ -+ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/* release WLON reset 0x04[16]=1*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1}, /*0x04[9] = 1 turn off MAC by HW state machine*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT1, 0}, /*wait till 0x04[9] = 0 polling until return 0 to disable*/ \ -+ {0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, BIT5}, /*0x00[5] = 1b'1 analog Ips to digital ,1:isolation*/ \ -+ {0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0}, /*0x20[0] = 1b'0 disable LDOA12 MACRO block*/ \ -+ -+ -+#define RTL8821A_TRANS_CARDEMU_TO_SUS \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4 | BIT3, (BIT4 | BIT3)}, /*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3 | BIT4, BIT3}, /*0x04[12:11] = 2b'01 enable WL suspend*/ \ -+ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, BIT4}, /*0x23[4] = 1b'1 12H LDO enter sleep mode*/ \ -+ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07[7:0] = 0x20 SDIO SOP option to disable BG/MB/ACK/SWR*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3 | BIT4, BIT3 | BIT4}, /*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/ \ -+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, BIT0}, /*Set SDIO suspend local register*/ \ -+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, 0}, /*wait power state to suspend*/ -+ -+#define RTL8821A_TRANS_SUS_TO_CARDEMU \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3 | BIT7, 0}, /*clear suspend enable and power down enable*/ \ -+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, 0}, /*Set SDIO suspend local register*/ \ -+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, BIT1}, /*wait power state to suspend*/\ -+ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*0x23[4] = 1b'0 12H LDO enter normal mode*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3 | BIT4, 0}, /*0x04[12:11] = 2b'01enable WL suspend*/ -+ -+#define RTL8821A_TRANS_CARDEMU_TO_CARDDIS \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07 = 0x20 , SOP option to disable BG/MB*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3 | BIT4, BIT3}, /*0x04[12:11] = 2b'01 enable WL suspend*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, BIT2}, /*0x04[10] = 1, enable SW LPS*/ \ -+ {0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 1}, /*0x48[16] = 1 to enable GPIO9 as EXT WAKEUP*/ \ -+ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, BIT4}, /*0x23[4] = 1b'1 12H LDO enter sleep mode*/ \ -+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, BIT0}, /*Set SDIO suspend local register*/ \ -+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, 0}, /*wait power state to suspend*/ -+ -+#define RTL8821A_TRANS_CARDDIS_TO_CARDEMU \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3 | BIT7, 0}, /*clear suspend enable and power down enable*/ \ -+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, 0}, /*Set SDIO suspend local register*/ \ -+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, BIT1}, /*wait power state to suspend*/\ -+ {0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0}, /*0x48[16] = 0 to disable GPIO9 as EXT WAKEUP*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3 | BIT4, 0}, /*0x04[12:11] = 2b'01enable WL suspend*/\ -+ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*0x23[4] = 1b'0 12H LDO enter normal mode*/ \ -+ {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/*PCIe DMA start*/ -+ -+ -+#define RTL8821A_TRANS_CARDEMU_TO_PDN \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, BIT4}, /*0x23[4] = 1b'1 12H LDO enter sleep mode*/ \ -+ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK | PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07[7:0] = 0x20 SOP option to disable BG/MB/ACK/SWR*/ \ -+ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0},/* 0x04[16] = 0*/\ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, BIT7},/* 0x04[15] = 1*/ -+ -+#define RTL8821A_TRANS_PDN_TO_CARDEMU \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0},/* 0x04[15] = 0*/ -+ -+#define RTL8821A_TRANS_ACT_TO_LPS \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF},/*PCIe DMA stop*/ \ -+ {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF},/*Tx Pause*/ \ -+ {0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ -+ {0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ -+ {0x05FA, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ -+ {0x05FB, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ -+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0},/*CCK and OFDM are disabled, and clock are gated*/ \ -+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US},/*Delay 1us*/ \ -+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0},/*Whole BB is reset*/ \ -+ {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x03},/*Reset MAC TRX*/ \ -+ {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0},/*check if removed later*/ \ -+ {0x0093, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00},/*When driver enter Sus/ Disable, enable LOP for BT*/ \ -+ {0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, BIT5},/*Respond TxOK to scheduler*/ \ -+ -+ -+#define RTL8821A_TRANS_LPS_TO_ACT \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ {0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, 0xFF, 0x84}, /*SDIO RPWM*/\ -+ {0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*USB RPWM*/\ -+ {0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*PCIe RPWM*/\ -+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS}, /*Delay*/\ -+ {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*. 0x08[4] = 0 switch TSF to 40M*/\ -+ {0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT7, 0}, /*Polling 0x109[7]=0 TSF in 40M*/\ -+ {0x0029, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6 | BIT7, 0}, /*. 0x29[7:6] = 2b'00 enable BB clock*/\ -+ {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1}, /*. 0x101[1] = 1*/\ -+ {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF}, /*. 0x100[7:0] = 0xFF enable WMAC TRX*/\ -+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1 | BIT0, BIT1 | BIT0}, /*. 0x02[1:0] = 2b'11 enable BB macro*/\ -+ {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}, /*. 0x522 = 0*/ -+ -+#define RTL8821A_TRANS_END \ -+ /* format */ \ -+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ -+ {0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, 0, PWR_CMD_END, 0, 0}, -+ -+ -+ extern WLAN_PWR_CFG rtl8821A_power_on_flow[RTL8821A_TRANS_CARDEMU_TO_ACT_STEPS + RTL8821A_TRANS_END_STEPS]; -+ extern WLAN_PWR_CFG rtl8821A_radio_off_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8821A_TRANS_END_STEPS]; -+ extern WLAN_PWR_CFG rtl8821A_card_disable_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8821A_TRANS_CARDEMU_TO_PDN_STEPS + RTL8821A_TRANS_END_STEPS]; -+ extern WLAN_PWR_CFG rtl8821A_card_enable_flow[RTL8821A_TRANS_CARDDIS_TO_CARDEMU_STEPS + RTL8821A_TRANS_CARDEMU_TO_ACT_STEPS + RTL8821A_TRANS_END_STEPS]; -+ extern WLAN_PWR_CFG rtl8821A_suspend_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8821A_TRANS_CARDEMU_TO_SUS_STEPS + RTL8821A_TRANS_END_STEPS]; -+ extern WLAN_PWR_CFG rtl8821A_resume_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8821A_TRANS_CARDEMU_TO_SUS_STEPS + RTL8821A_TRANS_END_STEPS]; -+ extern WLAN_PWR_CFG rtl8821A_hwpdn_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8821A_TRANS_CARDEMU_TO_PDN_STEPS + RTL8821A_TRANS_END_STEPS]; -+ extern WLAN_PWR_CFG rtl8821A_enter_lps_flow[RTL8821A_TRANS_ACT_TO_LPS_STEPS + RTL8821A_TRANS_END_STEPS]; -+ extern WLAN_PWR_CFG rtl8821A_leave_lps_flow[RTL8821A_TRANS_LPS_TO_ACT_STEPS + RTL8821A_TRANS_END_STEPS]; -+ -+#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/HalPwrSeqCmd.h linux-5.8/3rdparty/rtl8812au/include/HalPwrSeqCmd.h -new file mode 100644 -index 000000000..f67ed22d1 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/HalPwrSeqCmd.h -@@ -0,0 +1,130 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+#ifndef __HALPWRSEQCMD_H__ -+#define __HALPWRSEQCMD_H__ -+ -+#include -+ -+/*---------------------------------------------*/ -+/* 3 The value of cmd: 4 bits -+ *---------------------------------------------*/ -+#define PWR_CMD_READ 0x00 -+/* offset: the read register offset -+ * msk: the mask of the read value -+ * value: N/A, left by 0 -+ * note: dirver shall implement this function by read & msk */ -+ -+#define PWR_CMD_WRITE 0x01 -+/* offset: the read register offset -+ * msk: the mask of the write bits -+ * value: write value -+ * note: driver shall implement this cmd by read & msk after write */ -+ -+#define PWR_CMD_POLLING 0x02 -+/* offset: the read register offset -+ * msk: the mask of the polled value -+ * value: the value to be polled, masked by the msd field. -+ * note: driver shall implement this cmd by -+ * do { -+ * if( (Read(offset) & msk) == (value & msk) ) -+ * break; -+ * } while(not timeout); */ -+ -+#define PWR_CMD_DELAY 0x03 -+/* offset: the value to delay -+ * msk: N/A -+ * value: the unit of delay, 0: us, 1: ms */ -+ -+#define PWR_CMD_END 0x04 -+/* offset: N/A -+ * msk: N/A -+ * value: N/A */ -+ -+/*---------------------------------------------*/ -+/* 3 The value of base: 4 bits -+ *--------------------------------------------- -+ * define the base address of each block */ -+#define PWR_BASEADDR_MAC 0x00 -+#define PWR_BASEADDR_USB 0x01 -+#define PWR_BASEADDR_PCIE 0x02 -+#define PWR_BASEADDR_SDIO 0x03 -+ -+/*---------------------------------------------*/ -+/* 3 The value of interface_msk: 4 bits -+ *---------------------------------------------*/ -+#define PWR_INTF_SDIO_MSK BIT(0) -+#define PWR_INTF_USB_MSK BIT(1) -+#define PWR_INTF_PCI_MSK BIT(2) -+#define PWR_INTF_ALL_MSK (BIT(0) | BIT(1) | BIT(2) | BIT(3)) -+ -+/*---------------------------------------------*/ -+/* 3 The value of fab_msk: 4 bits -+ *---------------------------------------------*/ -+#define PWR_FAB_TSMC_MSK BIT(0) -+#define PWR_FAB_UMC_MSK BIT(1) -+#define PWR_FAB_ALL_MSK (BIT(0) | BIT(1) | BIT(2) | BIT(3)) -+ -+/*---------------------------------------------*/ -+/* 3 The value of cut_msk: 8 bits -+ *---------------------------------------------*/ -+#define PWR_CUT_TESTCHIP_MSK BIT(0) -+#define PWR_CUT_A_MSK BIT(1) -+#define PWR_CUT_B_MSK BIT(2) -+#define PWR_CUT_C_MSK BIT(3) -+#define PWR_CUT_D_MSK BIT(4) -+#define PWR_CUT_E_MSK BIT(5) -+#define PWR_CUT_F_MSK BIT(6) -+#define PWR_CUT_G_MSK BIT(7) -+#define PWR_CUT_ALL_MSK 0xFF -+ -+ -+typedef enum _PWRSEQ_CMD_DELAY_UNIT_ { -+ PWRSEQ_DELAY_US, -+ PWRSEQ_DELAY_MS, -+} PWRSEQ_DELAY_UNIT; -+ -+typedef struct _WL_PWR_CFG_ { -+ u16 offset; -+ u8 cut_msk; -+ u8 fab_msk:4; -+ u8 interface_msk:4; -+ u8 base:4; -+ u8 cmd:4; -+ u8 msk; -+ u8 value; -+} WLAN_PWR_CFG, *PWLAN_PWR_CFG; -+ -+ -+#define GET_PWR_CFG_OFFSET(__PWR_CMD) ((__PWR_CMD).offset) -+#define GET_PWR_CFG_CUT_MASK(__PWR_CMD) ((__PWR_CMD).cut_msk) -+#define GET_PWR_CFG_FAB_MASK(__PWR_CMD) ((__PWR_CMD).fab_msk) -+#define GET_PWR_CFG_INTF_MASK(__PWR_CMD) ((__PWR_CMD).interface_msk) -+#define GET_PWR_CFG_BASE(__PWR_CMD) ((__PWR_CMD).base) -+#define GET_PWR_CFG_CMD(__PWR_CMD) ((__PWR_CMD).cmd) -+#define GET_PWR_CFG_MASK(__PWR_CMD) ((__PWR_CMD).msk) -+#define GET_PWR_CFG_VALUE(__PWR_CMD) ((__PWR_CMD).value) -+ -+ -+/* ******************************************************************************** -+ * Prototype of protected function. -+ * ******************************************************************************** */ -+u8 HalPwrSeqCmdParsing( -+ PADAPTER padapter, -+ u8 CutVersion, -+ u8 FabVersion, -+ u8 InterfaceType, -+ WLAN_PWR_CFG PwrCfgCmd[]); -+ -+#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/HalVerDef.h linux-5.8/3rdparty/rtl8812au/include/HalVerDef.h -new file mode 100644 -index 000000000..ab1c578db ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/HalVerDef.h -@@ -0,0 +1,201 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+#ifndef __HAL_VERSION_DEF_H__ -+#define __HAL_VERSION_DEF_H__ -+ -+#define TRUE _TRUE -+#define FALSE _FALSE -+ -+/* HAL_IC_TYPE_E */ -+typedef enum tag_HAL_IC_Type_Definition { -+ CHIP_8192S = 0, -+ CHIP_8188C = 1, -+ CHIP_8192C = 2, -+ CHIP_8192D = 3, -+ CHIP_8723A = 4, -+ CHIP_8188E = 5, -+ CHIP_8812 = 6, -+ CHIP_8821 = 7, -+ CHIP_8723B = 8, -+ CHIP_8192E = 9, -+ CHIP_8814A = 10, -+ CHIP_8703B = 11, -+ CHIP_8188F = 12, -+ CHIP_8822B = 13, -+ CHIP_8723D = 14, -+ CHIP_8821C = 15, -+ CHIP_8710B = 16, -+ CHIP_8192F = 17, -+ CHIP_8188GTV = 18, -+} HAL_IC_TYPE_E; -+ -+/* HAL_CHIP_TYPE_E */ -+typedef enum tag_HAL_CHIP_Type_Definition { -+ TEST_CHIP = 0, -+ NORMAL_CHIP = 1, -+ FPGA = 2, -+} HAL_CHIP_TYPE_E; -+ -+/* HAL_CUT_VERSION_E */ -+typedef enum tag_HAL_Cut_Version_Definition { -+ A_CUT_VERSION = 0, -+ B_CUT_VERSION = 1, -+ C_CUT_VERSION = 2, -+ D_CUT_VERSION = 3, -+ E_CUT_VERSION = 4, -+ F_CUT_VERSION = 5, -+ G_CUT_VERSION = 6, -+ H_CUT_VERSION = 7, -+ I_CUT_VERSION = 8, -+ J_CUT_VERSION = 9, -+ K_CUT_VERSION = 10, -+} HAL_CUT_VERSION_E; -+ -+/* HAL_Manufacturer */ -+typedef enum tag_HAL_Manufacturer_Version_Definition { -+ CHIP_VENDOR_TSMC = 0, -+ CHIP_VENDOR_UMC = 1, -+ CHIP_VENDOR_SMIC = 2, -+} HAL_VENDOR_E; -+ -+typedef enum tag_HAL_RF_Type_Definition { -+ RF_TYPE_1T1R = 0, -+ RF_TYPE_1T2R = 1, -+ RF_TYPE_2T2R = 2, -+ RF_TYPE_2T3R = 3, -+ RF_TYPE_2T4R = 4, -+ RF_TYPE_3T3R = 5, -+ RF_TYPE_3T4R = 6, -+ RF_TYPE_4T4R = 7, -+} HAL_RF_TYPE_E; -+ -+typedef struct tag_HAL_VERSION { -+ HAL_IC_TYPE_E ICType; -+ HAL_CHIP_TYPE_E ChipType; -+ HAL_CUT_VERSION_E CUTVersion; -+ HAL_VENDOR_E VendorType; -+ HAL_RF_TYPE_E RFType; -+ u8 ROMVer; -+} HAL_VERSION, *PHAL_VERSION; -+ -+/* VERSION_8192C VersionID; -+ * HAL_VERSION VersionID; */ -+ -+/* Get element */ -+#define GET_CVID_IC_TYPE(version) ((HAL_IC_TYPE_E)(((HAL_VERSION)version).ICType)) -+#define GET_CVID_CHIP_TYPE(version) ((HAL_CHIP_TYPE_E)(((HAL_VERSION)version).ChipType)) -+#define GET_CVID_RF_TYPE(version) ((HAL_RF_TYPE_E)(((HAL_VERSION)version).RFType)) -+#define GET_CVID_MANUFACTUER(version) ((HAL_VENDOR_E)(((HAL_VERSION)version).VendorType)) -+#define GET_CVID_CUT_VERSION(version) ((HAL_CUT_VERSION_E)(((HAL_VERSION)version).CUTVersion)) -+#define GET_CVID_ROM_VERSION(version) ((((HAL_VERSION)version).ROMVer) & ROM_VERSION_MASK) -+ -+/* ---------------------------------------------------------------------------- -+ * Common Macro. -- -+ * ---------------------------------------------------------------------------- -+ * HAL_VERSION VersionID */ -+ -+/* HAL_IC_TYPE_E */ -+#if 0 -+ #define IS_81XXC(version) (((GET_CVID_IC_TYPE(version) == CHIP_8192C) || (GET_CVID_IC_TYPE(version) == CHIP_8188C)) ? TRUE : FALSE) -+ #define IS_8723_SERIES(version) ((GET_CVID_IC_TYPE(version) == CHIP_8723A) ? TRUE : FALSE) -+ #define IS_92D(version) ((GET_CVID_IC_TYPE(version) == CHIP_8192D) ? TRUE : FALSE) -+#endif -+ -+#define IS_8188E(version) ((GET_CVID_IC_TYPE(version) == CHIP_8188E) ? TRUE : FALSE) -+#define IS_8188F(version) ((GET_CVID_IC_TYPE(version) == CHIP_8188F) ? TRUE : FALSE) -+#define IS_8188GTV(version) ((GET_CVID_IC_TYPE(version) == CHIP_8188GTV) ? TRUE : FALSE) -+#define IS_8192E(version) ((GET_CVID_IC_TYPE(version) == CHIP_8192E) ? TRUE : FALSE) -+#define IS_8812_SERIES(version) ((GET_CVID_IC_TYPE(version) == CHIP_8812) ? TRUE : FALSE) -+#define IS_8821_SERIES(version) ((GET_CVID_IC_TYPE(version) == CHIP_8821) ? TRUE : FALSE) -+#define IS_8814A_SERIES(version) ((GET_CVID_IC_TYPE(version) == CHIP_8814A) ? TRUE : FALSE) -+#define IS_8723B_SERIES(version) ((GET_CVID_IC_TYPE(version) == CHIP_8723B) ? TRUE : FALSE) -+#define IS_8703B_SERIES(version) ((GET_CVID_IC_TYPE(version) == CHIP_8703B) ? TRUE : FALSE) -+#define IS_8822B_SERIES(version) ((GET_CVID_IC_TYPE(version) == CHIP_8822B) ? TRUE : FALSE) -+#define IS_8821C_SERIES(version) ((GET_CVID_IC_TYPE(version) == CHIP_8821C) ? TRUE : FALSE) -+#define IS_8723D_SERIES(version) ((GET_CVID_IC_TYPE(version) == CHIP_8723D) ? TRUE : FALSE) -+#define IS_8710B_SERIES(version) ((GET_CVID_IC_TYPE(version) == CHIP_8710B) ? TRUE : FALSE) -+ -+#define IS_8192F_SERIES(version)\ -+ ((GET_CVID_IC_TYPE(version) == CHIP_8192F) ? TRUE : FALSE) -+/* HAL_CHIP_TYPE_E */ -+#define IS_TEST_CHIP(version) ((GET_CVID_CHIP_TYPE(version) == TEST_CHIP) ? TRUE : FALSE) -+#define IS_NORMAL_CHIP(version) ((GET_CVID_CHIP_TYPE(version) == NORMAL_CHIP) ? TRUE : FALSE) -+ -+/* HAL_CUT_VERSION_E */ -+#define IS_A_CUT(version) ((GET_CVID_CUT_VERSION(version) == A_CUT_VERSION) ? TRUE : FALSE) -+#define IS_B_CUT(version) ((GET_CVID_CUT_VERSION(version) == B_CUT_VERSION) ? TRUE : FALSE) -+#define IS_C_CUT(version) ((GET_CVID_CUT_VERSION(version) == C_CUT_VERSION) ? TRUE : FALSE) -+#define IS_D_CUT(version) ((GET_CVID_CUT_VERSION(version) == D_CUT_VERSION) ? TRUE : FALSE) -+#define IS_E_CUT(version) ((GET_CVID_CUT_VERSION(version) == E_CUT_VERSION) ? TRUE : FALSE) -+#define IS_F_CUT(version) ((GET_CVID_CUT_VERSION(version) == F_CUT_VERSION) ? TRUE : FALSE) -+#define IS_I_CUT(version) ((GET_CVID_CUT_VERSION(version) == I_CUT_VERSION) ? TRUE : FALSE) -+#define IS_J_CUT(version) ((GET_CVID_CUT_VERSION(version) == J_CUT_VERSION) ? TRUE : FALSE) -+#define IS_K_CUT(version) ((GET_CVID_CUT_VERSION(version) == K_CUT_VERSION) ? TRUE : FALSE) -+ -+/* HAL_VENDOR_E */ -+#define IS_CHIP_VENDOR_TSMC(version) ((GET_CVID_MANUFACTUER(version) == CHIP_VENDOR_TSMC) ? TRUE : FALSE) -+#define IS_CHIP_VENDOR_UMC(version) ((GET_CVID_MANUFACTUER(version) == CHIP_VENDOR_UMC) ? TRUE : FALSE) -+#define IS_CHIP_VENDOR_SMIC(version) ((GET_CVID_MANUFACTUER(version) == CHIP_VENDOR_SMIC) ? TRUE : FALSE) -+ -+/* HAL_RF_TYPE_E */ -+#define IS_1T1R(version) ((GET_CVID_RF_TYPE(version) == RF_TYPE_1T1R) ? TRUE : FALSE) -+#define IS_1T2R(version) ((GET_CVID_RF_TYPE(version) == RF_TYPE_1T2R) ? TRUE : FALSE) -+#define IS_2T2R(version) ((GET_CVID_RF_TYPE(version) == RF_TYPE_2T2R) ? TRUE : FALSE) -+#define IS_3T3R(version) ((GET_CVID_RF_TYPE(version) == RF_TYPE_3T3R) ? TRUE : FALSE) -+#define IS_3T4R(version) ((GET_CVID_RF_TYPE(version) == RF_TYPE_3T4R) ? TRUE : FALSE) -+#define IS_4T4R(version) ((GET_CVID_RF_TYPE(version) == RF_TYPE_4T4R) ? TRUE : FALSE) -+ -+ -+ -+/* ---------------------------------------------------------------------------- -+ * Chip version Macro. -- -+ * ---------------------------------------------------------------------------- */ -+#if 0 -+ #define IS_81XXC_TEST_CHIP(version) ((IS_81XXC(version) && (!IS_NORMAL_CHIP(version))) ? TRUE : FALSE) -+ -+ #define IS_92C_SERIAL(version) ((IS_81XXC(version) && IS_2T2R(version)) ? TRUE : FALSE) -+ #define IS_81xxC_VENDOR_UMC_A_CUT(version) (IS_81XXC(version) ? (IS_CHIP_VENDOR_UMC(version) ? (IS_A_CUT(version) ? TRUE : FALSE) : FALSE) : FALSE) -+ #define IS_81xxC_VENDOR_UMC_B_CUT(version) (IS_81XXC(version) ? (IS_CHIP_VENDOR_UMC(version) ? (IS_B_CUT(version) ? TRUE : FALSE) : FALSE) : FALSE) -+ #define IS_81xxC_VENDOR_UMC_C_CUT(version) (IS_81XXC(version) ? (IS_CHIP_VENDOR_UMC(version) ? (IS_C_CUT(version) ? TRUE : FALSE) : FALSE) : FALSE) -+ -+ #define IS_NORMAL_CHIP92D(version) ((IS_92D(version)) ? ((GET_CVID_CHIP_TYPE(version) == NORMAL_CHIP) ? TRUE : FALSE) : FALSE) -+ -+ #define IS_92D_SINGLEPHY(version) ((IS_92D(version)) ? (IS_2T2R(version) ? TRUE : FALSE) : FALSE) -+ #define IS_92D_C_CUT(version) ((IS_92D(version)) ? (IS_C_CUT(version) ? TRUE : FALSE) : FALSE) -+ #define IS_92D_D_CUT(version) ((IS_92D(version)) ? (IS_D_CUT(version) ? TRUE : FALSE) : FALSE) -+ #define IS_92D_E_CUT(version) ((IS_92D(version)) ? (IS_E_CUT(version) ? TRUE : FALSE) : FALSE) -+ -+ #define IS_8723A_A_CUT(version) ((IS_8723_SERIES(version)) ? (IS_A_CUT(version) ? TRUE : FALSE) : FALSE) -+ #define IS_8723A_B_CUT(version) ((IS_8723_SERIES(version)) ? (IS_B_CUT(version) ? TRUE : FALSE) : FALSE) -+#endif -+#define IS_VENDOR_8188E_I_CUT_SERIES(_Adapter) ((IS_8188E(GET_HAL_DATA(_Adapter)->version_id)) ? ((GET_CVID_CUT_VERSION(GET_HAL_DATA(_Adapter)->version_id) >= I_CUT_VERSION) ? TRUE : FALSE) : FALSE) -+#define IS_VENDOR_8812A_TEST_CHIP(_Adapter) ((IS_8812_SERIES(GET_HAL_DATA(_Adapter)->version_id)) ? ((IS_NORMAL_CHIP(GET_HAL_DATA(_Adapter)->version_id)) ? FALSE : TRUE) : FALSE) -+#define IS_VENDOR_8812A_MP_CHIP(_Adapter) ((IS_8812_SERIES(GET_HAL_DATA(_Adapter)->version_id)) ? ((IS_NORMAL_CHIP(GET_HAL_DATA(_Adapter)->version_id)) ? TRUE : FALSE) : FALSE) -+#define IS_VENDOR_8812A_C_CUT(_Adapter) ((IS_8812_SERIES(GET_HAL_DATA(_Adapter)->version_id)) ? ((GET_CVID_CUT_VERSION(GET_HAL_DATA(_Adapter)->version_id) == C_CUT_VERSION) ? TRUE : FALSE) : FALSE) -+ -+#define IS_VENDOR_8821A_TEST_CHIP(_Adapter) ((IS_8821_SERIES(GET_HAL_DATA(_Adapter)->version_id)) ? ((IS_NORMAL_CHIP(GET_HAL_DATA(_Adapter)->version_id)) ? FALSE : TRUE) : FALSE) -+#define IS_VENDOR_8821A_MP_CHIP(_Adapter) ((IS_8821_SERIES(GET_HAL_DATA(_Adapter)->version_id)) ? ((IS_NORMAL_CHIP(GET_HAL_DATA(_Adapter)->version_id)) ? TRUE : FALSE) : FALSE) -+ -+#define IS_VENDOR_8192E_B_CUT(_Adapter) ((GET_CVID_CUT_VERSION(GET_HAL_DATA(_Adapter)->version_id) == B_CUT_VERSION) ? TRUE : FALSE) -+ -+#define IS_VENDOR_8723B_TEST_CHIP(_Adapter) ((IS_8723B_SERIES(GET_HAL_DATA(_Adapter)->version_id)) ? ((IS_NORMAL_CHIP(GET_HAL_DATA(_Adapter)->version_id)) ? FALSE : TRUE) : FALSE) -+#define IS_VENDOR_8723B_MP_CHIP(_Adapter) ((IS_8723B_SERIES(GET_HAL_DATA(_Adapter)->version_id)) ? ((IS_NORMAL_CHIP(GET_HAL_DATA(_Adapter)->version_id)) ? TRUE : FALSE) : FALSE) -+ -+#define IS_VENDOR_8703B_TEST_CHIP(_Adapter) ((IS_8703B_SERIES(GET_HAL_DATA(_Adapter)->version_id)) ? ((IS_NORMAL_CHIP(GET_HAL_DATA(_Adapter)->version_id)) ? FALSE : TRUE) : FALSE) -+#define IS_VENDOR_8703B_MP_CHIP(_Adapter) ((IS_8703B_SERIES(GET_HAL_DATA(_Adapter)->version_id)) ? ((IS_NORMAL_CHIP(GET_HAL_DATA(_Adapter)->version_id)) ? TRUE : FALSE) : FALSE) -+#define IS_VENDOR_8814A_TEST_CHIP(_Adapter) ((IS_8814A_SERIES(GET_HAL_DATA(_Adapter)->version_id)) ? ((IS_NORMAL_CHIP(GET_HAL_DATA(_Adapter)->version_id)) ? FALSE : TRUE) : FALSE) -+#define IS_VENDOR_8814A_MP_CHIP(_Adapter) ((IS_8814A_SERIES(GET_HAL_DATA(_Adapter)->version_id)) ? ((IS_NORMAL_CHIP(GET_HAL_DATA(_Adapter)->version_id)) ? TRUE : FALSE) : FALSE) -+ -+#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/basic_types.h linux-5.8/3rdparty/rtl8812au/include/basic_types.h -new file mode 100644 -index 000000000..a324abaf9 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/basic_types.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/basic_types.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/basic_types.h +--- linux-5.11.4/3rdparty/rtl8812au/include/basic_types.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/basic_types.h 2021-03-07 18:16:17.084957471 +0200 @@ -0,0 +1,379 @@ +/****************************************************************************** + * @@ -372904,11 +366503,9 @@ index 000000000..a324abaf9 +#define TEST_FLAGS(__Flag, __testFlags) (((__Flag) & (__testFlags)) == (__testFlags)) + +#endif /* __BASIC_TYPES_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/byteorder/big_endian.h linux-5.8/3rdparty/rtl8812au/include/byteorder/big_endian.h -new file mode 100644 -index 000000000..6b1dc449e ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/byteorder/big_endian.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/byteorder/big_endian.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/byteorder/big_endian.h +--- linux-5.11.4/3rdparty/rtl8812au/include/byteorder/big_endian.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/byteorder/big_endian.h 2021-03-07 18:16:17.084957471 +0200 @@ -0,0 +1,82 @@ +/****************************************************************************** + * @@ -372992,11 +366589,9 @@ index 000000000..6b1dc449e +#include + +#endif /* _LINUX_BYTEORDER_BIG_ENDIAN_H */ -diff --git linux-5.8/3rdparty/rtl8812au/include/byteorder/generic.h linux-5.8/3rdparty/rtl8812au/include/byteorder/generic.h -new file mode 100644 -index 000000000..f85114bf7 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/byteorder/generic.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/byteorder/generic.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/byteorder/generic.h +--- linux-5.11.4/3rdparty/rtl8812au/include/byteorder/generic.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/byteorder/generic.h 2021-03-07 18:16:17.084957471 +0200 @@ -0,0 +1,207 @@ +/****************************************************************************** + * @@ -373205,11 +366800,9 @@ index 000000000..f85114bf7 +#endif + +#endif /* _LINUX_BYTEORDER_GENERIC_H */ -diff --git linux-5.8/3rdparty/rtl8812au/include/byteorder/little_endian.h linux-5.8/3rdparty/rtl8812au/include/byteorder/little_endian.h -new file mode 100644 -index 000000000..c4b64512f ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/byteorder/little_endian.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/byteorder/little_endian.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/byteorder/little_endian.h +--- linux-5.11.4/3rdparty/rtl8812au/include/byteorder/little_endian.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/byteorder/little_endian.h 2021-03-07 18:16:17.084957471 +0200 @@ -0,0 +1,84 @@ +/****************************************************************************** + * @@ -373295,153 +366888,9 @@ index 000000000..c4b64512f +#include + +#endif /* _LINUX_BYTEORDER_LITTLE_ENDIAN_H */ -diff --git linux-5.8/3rdparty/rtl8812au/include/byteorder/swab.h linux-5.8/3rdparty/rtl8812au/include/byteorder/swab.h -new file mode 100644 -index 000000000..a8dd46bd3 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/byteorder/swab.h -@@ -0,0 +1,136 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+#ifndef _LINUX_BYTEORDER_SWAB_H -+#define _LINUX_BYTEORDER_SWAB_H -+ -+#if !defined(CONFIG_PLATFORM_MSTAR) -+#ifndef __u16 -+ typedef unsigned short __u16; -+#endif -+ -+#ifndef __u32 -+ typedef unsigned int __u32; -+#endif -+ -+#ifndef __u8 -+ typedef unsigned char __u8; -+#endif -+ -+#ifndef __u64 -+ typedef unsigned long long __u64; -+#endif -+ -+ -+__inline static __u16 ___swab16(__u16 x) -+{ -+ __u16 __x = x; -+ return -+ (__u16)( -+ (((__u16)(__x)&(__u16)0x00ffU) << 8) | -+ (((__u16)(__x)&(__u16)0xff00U) >> 8)); -+ -+} -+ -+__inline static __u32 ___swab32(__u32 x) -+{ -+ __u32 __x = (x); -+ return (__u32)( -+ (((__u32)(__x)&(__u32)0x000000ffUL) << 24) | -+ (((__u32)(__x)&(__u32)0x0000ff00UL) << 8) | -+ (((__u32)(__x)&(__u32)0x00ff0000UL) >> 8) | -+ (((__u32)(__x)&(__u32)0xff000000UL) >> 24)); -+} -+ -+__inline static __u64 ___swab64(__u64 x) -+{ -+ __u64 __x = (x); -+ -+ return -+ (__u64)(\ -+ (__u64)(((__u64)(__x)&(__u64)0x00000000000000ffULL) << 56) | \ -+ (__u64)(((__u64)(__x)&(__u64)0x000000000000ff00ULL) << 40) | \ -+ (__u64)(((__u64)(__x)&(__u64)0x0000000000ff0000ULL) << 24) | \ -+ (__u64)(((__u64)(__x)&(__u64)0x00000000ff000000ULL) << 8) | \ -+ (__u64)(((__u64)(__x)&(__u64)0x000000ff00000000ULL) >> 8) | \ -+ (__u64)(((__u64)(__x)&(__u64)0x0000ff0000000000ULL) >> 24) | \ -+ (__u64)(((__u64)(__x)&(__u64)0x00ff000000000000ULL) >> 40) | \ -+ (__u64)(((__u64)(__x)&(__u64)0xff00000000000000ULL) >> 56)); -+ \ -+} -+#endif /* CONFIG_PLATFORM_MSTAR */ -+ -+#ifndef __arch__swab16 -+__inline static __u16 __arch__swab16(__u16 x) -+{ -+ return ___swab16(x); -+} -+ -+#endif -+ -+#ifndef __arch__swab32 -+__inline static __u32 __arch__swab32(__u32 x) -+{ -+ __u32 __tmp = (x) ; -+ return ___swab32(__tmp); -+} -+#endif -+ -+#ifndef __arch__swab64 -+ -+__inline static __u64 __arch__swab64(__u64 x) -+{ -+ __u64 __tmp = (x) ; -+ return ___swab64(__tmp); -+} -+ -+ -+#endif -+ -+#ifndef __swab16 -+ #define __swab16(x) __fswab16(x) -+ #define __swab32(x) __fswab32(x) -+ #define __swab64(x) __fswab64(x) -+#endif /* __swab16 */ -+ -+#ifdef PLATFORM_FREEBSD -+ __inline static __u16 __fswab16(__u16 x) -+#else -+ __inline static const __u16 __fswab16(__u16 x) -+#endif /* PLATFORM_FREEBSD */ -+{ -+ return __arch__swab16(x); -+} -+#ifdef PLATFORM_FREEBSD -+ __inline static __u32 __fswab32(__u32 x) -+#else -+ __inline static const __u32 __fswab32(__u32 x) -+#endif /* PLATFORM_FREEBSD */ -+{ -+ return __arch__swab32(x); -+} -+ -+#if defined(PLATFORM_LINUX) || defined(PLATFORM_WINDOWS) -+ #define swab16 __swab16 -+ #define swab32 __swab32 -+ #define swab64 __swab64 -+ #define swab16p __swab16p -+ #define swab32p __swab32p -+ #define swab64p __swab64p -+ #define swab16s __swab16s -+ #define swab32s __swab32s -+ #define swab64s __swab64s -+#endif -+ -+#endif /* _LINUX_BYTEORDER_SWAB_H */ -diff --git linux-5.8/3rdparty/rtl8812au/include/byteorder/swabb.h linux-5.8/3rdparty/rtl8812au/include/byteorder/swabb.h -new file mode 100644 -index 000000000..634519a0b ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/byteorder/swabb.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/byteorder/swabb.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/byteorder/swabb.h +--- linux-5.11.4/3rdparty/rtl8812au/include/byteorder/swabb.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/byteorder/swabb.h 2021-03-07 18:16:17.084957471 +0200 @@ -0,0 +1,151 @@ +/****************************************************************************** + * @@ -373594,11 +367043,149 @@ index 000000000..634519a0b +#endif + +#endif /* _LINUX_BYTEORDER_SWABB_H */ -diff --git linux-5.8/3rdparty/rtl8812au/include/circ_buf.h linux-5.8/3rdparty/rtl8812au/include/circ_buf.h -new file mode 100644 -index 000000000..7a5b8ef1a ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/circ_buf.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/byteorder/swab.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/byteorder/swab.h +--- linux-5.11.4/3rdparty/rtl8812au/include/byteorder/swab.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/byteorder/swab.h 2021-03-07 18:16:17.084957471 +0200 +@@ -0,0 +1,136 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++#ifndef _LINUX_BYTEORDER_SWAB_H ++#define _LINUX_BYTEORDER_SWAB_H ++ ++#if !defined(CONFIG_PLATFORM_MSTAR) ++#ifndef __u16 ++ typedef unsigned short __u16; ++#endif ++ ++#ifndef __u32 ++ typedef unsigned int __u32; ++#endif ++ ++#ifndef __u8 ++ typedef unsigned char __u8; ++#endif ++ ++#ifndef __u64 ++ typedef unsigned long long __u64; ++#endif ++ ++ ++__inline static __u16 ___swab16(__u16 x) ++{ ++ __u16 __x = x; ++ return ++ (__u16)( ++ (((__u16)(__x)&(__u16)0x00ffU) << 8) | ++ (((__u16)(__x)&(__u16)0xff00U) >> 8)); ++ ++} ++ ++__inline static __u32 ___swab32(__u32 x) ++{ ++ __u32 __x = (x); ++ return (__u32)( ++ (((__u32)(__x)&(__u32)0x000000ffUL) << 24) | ++ (((__u32)(__x)&(__u32)0x0000ff00UL) << 8) | ++ (((__u32)(__x)&(__u32)0x00ff0000UL) >> 8) | ++ (((__u32)(__x)&(__u32)0xff000000UL) >> 24)); ++} ++ ++__inline static __u64 ___swab64(__u64 x) ++{ ++ __u64 __x = (x); ++ ++ return ++ (__u64)(\ ++ (__u64)(((__u64)(__x)&(__u64)0x00000000000000ffULL) << 56) | \ ++ (__u64)(((__u64)(__x)&(__u64)0x000000000000ff00ULL) << 40) | \ ++ (__u64)(((__u64)(__x)&(__u64)0x0000000000ff0000ULL) << 24) | \ ++ (__u64)(((__u64)(__x)&(__u64)0x00000000ff000000ULL) << 8) | \ ++ (__u64)(((__u64)(__x)&(__u64)0x000000ff00000000ULL) >> 8) | \ ++ (__u64)(((__u64)(__x)&(__u64)0x0000ff0000000000ULL) >> 24) | \ ++ (__u64)(((__u64)(__x)&(__u64)0x00ff000000000000ULL) >> 40) | \ ++ (__u64)(((__u64)(__x)&(__u64)0xff00000000000000ULL) >> 56)); ++ \ ++} ++#endif /* CONFIG_PLATFORM_MSTAR */ ++ ++#ifndef __arch__swab16 ++__inline static __u16 __arch__swab16(__u16 x) ++{ ++ return ___swab16(x); ++} ++ ++#endif ++ ++#ifndef __arch__swab32 ++__inline static __u32 __arch__swab32(__u32 x) ++{ ++ __u32 __tmp = (x) ; ++ return ___swab32(__tmp); ++} ++#endif ++ ++#ifndef __arch__swab64 ++ ++__inline static __u64 __arch__swab64(__u64 x) ++{ ++ __u64 __tmp = (x) ; ++ return ___swab64(__tmp); ++} ++ ++ ++#endif ++ ++#ifndef __swab16 ++ #define __swab16(x) __fswab16(x) ++ #define __swab32(x) __fswab32(x) ++ #define __swab64(x) __fswab64(x) ++#endif /* __swab16 */ ++ ++#ifdef PLATFORM_FREEBSD ++ __inline static __u16 __fswab16(__u16 x) ++#else ++ __inline static const __u16 __fswab16(__u16 x) ++#endif /* PLATFORM_FREEBSD */ ++{ ++ return __arch__swab16(x); ++} ++#ifdef PLATFORM_FREEBSD ++ __inline static __u32 __fswab32(__u32 x) ++#else ++ __inline static const __u32 __fswab32(__u32 x) ++#endif /* PLATFORM_FREEBSD */ ++{ ++ return __arch__swab32(x); ++} ++ ++#if defined(PLATFORM_LINUX) || defined(PLATFORM_WINDOWS) ++ #define swab16 __swab16 ++ #define swab32 __swab32 ++ #define swab64 __swab64 ++ #define swab16p __swab16p ++ #define swab32p __swab32p ++ #define swab64p __swab64p ++ #define swab16s __swab16s ++ #define swab32s __swab32s ++ #define swab64s __swab64s ++#endif ++ ++#endif /* _LINUX_BYTEORDER_SWAB_H */ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/circ_buf.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/circ_buf.h +--- linux-5.11.4/3rdparty/rtl8812au/include/circ_buf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/circ_buf.h 2021-03-07 18:16:17.084957471 +0200 @@ -0,0 +1,23 @@ +/****************************************************************************** + * @@ -373623,11 +367210,9 @@ index 000000000..7a5b8ef1a + +#endif //_CIRC_BUF_H_ + -diff --git linux-5.8/3rdparty/rtl8812au/include/cmd_osdep.h linux-5.8/3rdparty/rtl8812au/include/cmd_osdep.h -new file mode 100644 -index 000000000..e4ba2b6d3 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/cmd_osdep.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/cmd_osdep.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/cmd_osdep.h +--- linux-5.11.4/3rdparty/rtl8812au/include/cmd_osdep.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/cmd_osdep.h 2021-03-07 18:16:17.084957471 +0200 @@ -0,0 +1,26 @@ +/****************************************************************************** + * @@ -373655,11 +367240,9 @@ index 000000000..e4ba2b6d3 +extern struct cmd_obj *_rtw_dequeue_cmd(_queue *queue); + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/cmn_info/rtw_sta_info.h linux-5.8/3rdparty/rtl8812au/include/cmn_info/rtw_sta_info.h -new file mode 100644 -index 000000000..6910098af ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/cmn_info/rtw_sta_info.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/cmn_info/rtw_sta_info.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/cmn_info/rtw_sta_info.h +--- linux-5.11.4/3rdparty/rtl8812au/include/cmn_info/rtw_sta_info.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/cmn_info/rtw_sta_info.h 2021-03-07 18:16:17.084957471 +0200 @@ -0,0 +1,257 @@ +/****************************************************************************** + * @@ -373918,11 +367501,9 @@ index 000000000..6910098af +/*--------------------Function declaration-----------------------------*/ + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/custom_gpio.h linux-5.8/3rdparty/rtl8812au/include/custom_gpio.h -new file mode 100644 -index 000000000..49411b662 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/custom_gpio.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/custom_gpio.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/custom_gpio.h +--- linux-5.11.4/3rdparty/rtl8812au/include/custom_gpio.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/custom_gpio.h 2021-03-07 18:16:17.084957471 +0200 @@ -0,0 +1,46 @@ +/****************************************************************************** + * @@ -373970,11 +367551,9 @@ index 000000000..49411b662 +extern void rtw_wifi_gpio_wlan_ctrl(int onoff); + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/drv_conf.h linux-5.8/3rdparty/rtl8812au/include/drv_conf.h -new file mode 100644 -index 000000000..9fac340fd ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/drv_conf.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/drv_conf.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/drv_conf.h +--- linux-5.11.4/3rdparty/rtl8812au/include/drv_conf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/drv_conf.h 2021-03-07 18:16:17.084957471 +0200 @@ -0,0 +1,510 @@ +/****************************************************************************** + * @@ -374486,11 +368065,152 @@ index 000000000..9fac340fd +#endif + +#endif /* __DRV_CONF_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/drv_types.h linux-5.8/3rdparty/rtl8812au/include/drv_types.h -new file mode 100644 -index 000000000..e52608d59 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/drv_types.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/drv_types_ce.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/drv_types_ce.h +--- linux-5.11.4/3rdparty/rtl8812au/include/drv_types_ce.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/drv_types_ce.h 2021-03-07 18:16:17.085957519 +0200 +@@ -0,0 +1,86 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++#ifndef __DRV_TYPES_CE_H__ ++#define __DRV_TYPES_CE_H__ ++ ++#include ++#include ++ ++#include ++ ++#define MAX_ACTIVE_REG_PATH 256 ++ ++#define MAX_MCAST_LIST_NUM 32 ++ ++ ++ ++/* for ioctl */ ++#define MAKE_DRIVER_VERSION(_MainVer, _MinorVer) ((((u32)(_MainVer))<<16)+_MinorVer) ++ ++#define NIC_HEADER_SIZE 14 /* !< can be moved to typedef.h */ ++#define NIC_MAX_PACKET_SIZE 1514 /* !< can be moved to typedef.h */ ++#define NIC_MAX_SEND_PACKETS 10 /* max number of send packets the MiniportSendPackets function can accept, can be moved to typedef.h */ ++#define NIC_VENDOR_DRIVER_VERSION MAKE_DRIVER_VERSION(0, 001) /* !< can be moved to typedef.h */ ++#define NIC_MAX_PACKET_SIZE 1514 /* !< can be moved to typedef.h */ ++ ++typedef struct _MP_REG_ENTRY { ++ ++ NDIS_STRING RegName; /* variable name text */ ++ BOOLEAN bRequired; /* 1->required, 0->optional */ ++ ++ u8 Type; /* NdisParameterInteger/NdisParameterHexInteger/NdisParameterStringle/NdisParameterMultiString */ ++ uint FieldOffset; /* offset to MP_ADAPTER field */ ++ uint FieldSize; /* size (in bytes) of the field */ ++ ++#ifdef UNDER_AMD64 ++ u64 Default; ++#else ++ u32 Default; /* default value to use */ ++#endif ++ ++ u32 Min; /* minimum value allowed */ ++ u32 Max; /* maximum value allowed */ ++} MP_REG_ENTRY, *PMP_REG_ENTRY; ++ ++#ifdef CONFIG_USB_HCI ++typedef struct _USB_EXTENSION { ++ LPCUSB_FUNCS _lpUsbFuncs; ++ USB_HANDLE _hDevice; ++ PVOID pAdapter; ++ ++#if 0 ++ USB_ENDPOINT_DESCRIPTOR _endpACLIn; ++ USB_ENDPOINT_DESCRIPTOR _endpACLOutHigh; ++ USB_ENDPOINT_DESCRIPTOR _endpACLOutNormal; ++ ++ USB_PIPE pPipeIn; ++ USB_PIPE pPipeOutNormal; ++ USB_PIPE pPipeOutHigh; ++#endif ++ ++} USB_EXTENSION, *PUSB_EXTENSION; ++#endif ++ ++ ++typedef struct _OCTET_STRING { ++ u8 *Octet; ++ u16 Length; ++} OCTET_STRING, *POCTET_STRING; ++ ++ ++ ++ ++ ++#endif +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/drv_types_gspi.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/drv_types_gspi.h +--- linux-5.11.4/3rdparty/rtl8812au/include/drv_types_gspi.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/drv_types_gspi.h 2021-03-07 18:16:17.085957519 +0200 +@@ -0,0 +1,49 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++#ifndef __DRV_TYPES_GSPI_H__ ++#define __DRV_TYPES_GSPI_H__ ++ ++/* SPI Header Files */ ++#ifdef PLATFORM_LINUX ++ #include ++ #include ++ #include ++ /* #include */ ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++#endif ++ ++ ++typedef struct gspi_data { ++ u8 func_number; ++ ++ u8 tx_block_mode; ++ u8 rx_block_mode; ++ u32 block_transfer_len; ++ ++#ifdef PLATFORM_LINUX ++ struct spi_device *func; ++ ++ struct workqueue_struct *priv_wq; ++ struct delayed_work irq_work; ++#endif ++} GSPI_DATA, *PGSPI_DATA; ++ ++#endif /* #ifndef __DRV_TYPES_GSPI_H__ */ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/drv_types.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/drv_types.h +--- linux-5.11.4/3rdparty/rtl8812au/include/drv_types.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/drv_types.h 2021-03-07 18:16:17.085957519 +0200 @@ -0,0 +1,1834 @@ +/****************************************************************************** + * @@ -376326,158 +370046,9 @@ index 000000000..e52608d59 +#endif + +#endif /* __DRV_TYPES_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/drv_types_ce.h linux-5.8/3rdparty/rtl8812au/include/drv_types_ce.h -new file mode 100644 -index 000000000..c00dea8e6 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/drv_types_ce.h -@@ -0,0 +1,86 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+#ifndef __DRV_TYPES_CE_H__ -+#define __DRV_TYPES_CE_H__ -+ -+#include -+#include -+ -+#include -+ -+#define MAX_ACTIVE_REG_PATH 256 -+ -+#define MAX_MCAST_LIST_NUM 32 -+ -+ -+ -+/* for ioctl */ -+#define MAKE_DRIVER_VERSION(_MainVer, _MinorVer) ((((u32)(_MainVer))<<16)+_MinorVer) -+ -+#define NIC_HEADER_SIZE 14 /* !< can be moved to typedef.h */ -+#define NIC_MAX_PACKET_SIZE 1514 /* !< can be moved to typedef.h */ -+#define NIC_MAX_SEND_PACKETS 10 /* max number of send packets the MiniportSendPackets function can accept, can be moved to typedef.h */ -+#define NIC_VENDOR_DRIVER_VERSION MAKE_DRIVER_VERSION(0, 001) /* !< can be moved to typedef.h */ -+#define NIC_MAX_PACKET_SIZE 1514 /* !< can be moved to typedef.h */ -+ -+typedef struct _MP_REG_ENTRY { -+ -+ NDIS_STRING RegName; /* variable name text */ -+ BOOLEAN bRequired; /* 1->required, 0->optional */ -+ -+ u8 Type; /* NdisParameterInteger/NdisParameterHexInteger/NdisParameterStringle/NdisParameterMultiString */ -+ uint FieldOffset; /* offset to MP_ADAPTER field */ -+ uint FieldSize; /* size (in bytes) of the field */ -+ -+#ifdef UNDER_AMD64 -+ u64 Default; -+#else -+ u32 Default; /* default value to use */ -+#endif -+ -+ u32 Min; /* minimum value allowed */ -+ u32 Max; /* maximum value allowed */ -+} MP_REG_ENTRY, *PMP_REG_ENTRY; -+ -+#ifdef CONFIG_USB_HCI -+typedef struct _USB_EXTENSION { -+ LPCUSB_FUNCS _lpUsbFuncs; -+ USB_HANDLE _hDevice; -+ PVOID pAdapter; -+ -+#if 0 -+ USB_ENDPOINT_DESCRIPTOR _endpACLIn; -+ USB_ENDPOINT_DESCRIPTOR _endpACLOutHigh; -+ USB_ENDPOINT_DESCRIPTOR _endpACLOutNormal; -+ -+ USB_PIPE pPipeIn; -+ USB_PIPE pPipeOutNormal; -+ USB_PIPE pPipeOutHigh; -+#endif -+ -+} USB_EXTENSION, *PUSB_EXTENSION; -+#endif -+ -+ -+typedef struct _OCTET_STRING { -+ u8 *Octet; -+ u16 Length; -+} OCTET_STRING, *POCTET_STRING; -+ -+ -+ -+ -+ -+#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/drv_types_gspi.h linux-5.8/3rdparty/rtl8812au/include/drv_types_gspi.h -new file mode 100644 -index 000000000..c22c49722 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/drv_types_gspi.h -@@ -0,0 +1,49 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+#ifndef __DRV_TYPES_GSPI_H__ -+#define __DRV_TYPES_GSPI_H__ -+ -+/* SPI Header Files */ -+#ifdef PLATFORM_LINUX -+ #include -+ #include -+ #include -+ /* #include */ -+ #include -+ #include -+ #include -+ #include -+ #include -+ #include -+ #include -+#endif -+ -+ -+typedef struct gspi_data { -+ u8 func_number; -+ -+ u8 tx_block_mode; -+ u8 rx_block_mode; -+ u32 block_transfer_len; -+ -+#ifdef PLATFORM_LINUX -+ struct spi_device *func; -+ -+ struct workqueue_struct *priv_wq; -+ struct delayed_work irq_work; -+#endif -+} GSPI_DATA, *PGSPI_DATA; -+ -+#endif /* #ifndef __DRV_TYPES_GSPI_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/drv_types_linux.h linux-5.8/3rdparty/rtl8812au/include/drv_types_linux.h -new file mode 100644 -index 000000000..91ca68b39 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/drv_types_linux.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/drv_types_linux.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/drv_types_linux.h +--- linux-5.11.4/3rdparty/rtl8812au/include/drv_types_linux.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/drv_types_linux.h 2021-03-07 18:16:17.085957519 +0200 @@ -0,0 +1,19 @@ +/****************************************************************************** + * @@ -376498,11 +370069,9 @@ index 000000000..91ca68b39 + + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/drv_types_pci.h linux-5.8/3rdparty/rtl8812au/include/drv_types_pci.h -new file mode 100644 -index 000000000..a3a492708 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/drv_types_pci.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/drv_types_pci.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/drv_types_pci.h +--- linux-5.11.4/3rdparty/rtl8812au/include/drv_types_pci.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/drv_types_pci.h 2021-03-07 18:16:17.085957519 +0200 @@ -0,0 +1,266 @@ +/****************************************************************************** + * @@ -376770,11 +370339,9 @@ index 000000000..a3a492708 + + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/drv_types_sdio.h linux-5.8/3rdparty/rtl8812au/include/drv_types_sdio.h -new file mode 100644 -index 000000000..9feca1216 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/drv_types_sdio.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/drv_types_sdio.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/drv_types_sdio.h +--- linux-5.11.4/3rdparty/rtl8812au/include/drv_types_sdio.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/drv_types_sdio.h 2021-03-07 18:16:17.085957519 +0200 @@ -0,0 +1,90 @@ +/****************************************************************************** + * @@ -376866,11 +370433,9 @@ index 000000000..9feca1216 +#define RTW_SDIO_ADDR_F0_CHK(a) (a&RTW_SDIO_ADDR_F0_BIT ? 1 : 0) + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/drv_types_xp.h linux-5.8/3rdparty/rtl8812au/include/drv_types_xp.h -new file mode 100644 -index 000000000..81c45047a ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/drv_types_xp.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/drv_types_xp.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/drv_types_xp.h +--- linux-5.11.4/3rdparty/rtl8812au/include/drv_types_xp.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/drv_types_xp.h 2021-03-07 18:16:17.085957519 +0200 @@ -0,0 +1,88 @@ +/****************************************************************************** + * @@ -376960,11 +370525,9 @@ index 000000000..81c45047a + + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/ethernet.h linux-5.8/3rdparty/rtl8812au/include/ethernet.h -new file mode 100644 -index 000000000..2bafa4d98 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/ethernet.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/ethernet.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/ethernet.h +--- linux-5.11.4/3rdparty/rtl8812au/include/ethernet.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/ethernet.h 2021-03-07 18:16:17.085957519 +0200 @@ -0,0 +1,36 @@ +/****************************************************************************** + * @@ -377002,11 +370565,9 @@ index 000000000..2bafa4d98 + + +#endif /* #ifndef __INC_ETHERNET_H */ -diff --git linux-5.8/3rdparty/rtl8812au/include/gspi_hal.h linux-5.8/3rdparty/rtl8812au/include/gspi_hal.h -new file mode 100644 -index 000000000..6da0f071d ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/gspi_hal.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/gspi_hal.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/gspi_hal.h +--- linux-5.11.4/3rdparty/rtl8812au/include/gspi_hal.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/gspi_hal.h 2021-03-07 18:16:17.085957519 +0200 @@ -0,0 +1,30 @@ +/****************************************************************************** + * @@ -377038,11 +370599,9 @@ index 000000000..6da0f071d +#endif + +#endif /* __GSPI_HAL_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/gspi_ops.h linux-5.8/3rdparty/rtl8812au/include/gspi_ops.h -new file mode 100644 -index 000000000..bcfaad2e0 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/gspi_ops.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/gspi_ops.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/gspi_ops.h +--- linux-5.11.4/3rdparty/rtl8812au/include/gspi_ops.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/gspi_ops.h 2021-03-07 18:16:17.085957519 +0200 @@ -0,0 +1,180 @@ +/****************************************************************************** + * @@ -377224,11 +370783,9 @@ index 000000000..bcfaad2e0 +#endif /* CONFIG_WOWLAN */ + +#endif /* __GSPI_OPS_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/gspi_ops_linux.h linux-5.8/3rdparty/rtl8812au/include/gspi_ops_linux.h -new file mode 100644 -index 000000000..0ba263de8 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/gspi_ops_linux.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/gspi_ops_linux.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/gspi_ops_linux.h +--- linux-5.11.4/3rdparty/rtl8812au/include/gspi_ops_linux.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/gspi_ops_linux.h 2021-03-07 18:16:17.085957519 +0200 @@ -0,0 +1,18 @@ +/****************************************************************************** + * @@ -377248,11 +370805,9 @@ index 000000000..0ba263de8 +#define __SDIO_OPS_LINUX_H__ + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/gspi_osintf.h linux-5.8/3rdparty/rtl8812au/include/gspi_osintf.h -new file mode 100644 -index 000000000..6393f779d ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/gspi_osintf.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/gspi_osintf.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/gspi_osintf.h +--- linux-5.11.4/3rdparty/rtl8812au/include/gspi_osintf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/gspi_osintf.h 2021-03-07 18:16:17.085957519 +0200 @@ -0,0 +1,25 @@ +/****************************************************************************** + * @@ -377279,11 +370834,9 @@ index 000000000..6393f779d +#endif + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/h2clbk.h linux-5.8/3rdparty/rtl8812au/include/h2clbk.h -new file mode 100644 -index 000000000..4e22afcd8 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/h2clbk.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/h2clbk.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/h2clbk.h +--- linux-5.11.4/3rdparty/rtl8812au/include/h2clbk.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/h2clbk.h 2021-03-07 18:16:17.085957519 +0200 @@ -0,0 +1,26 @@ +/****************************************************************************** + * @@ -377311,11 +370864,2681 @@ index 000000000..4e22afcd8 +void _lbk_evt(IN PADAPTER Adapter); + +void h2c_event_callback(unsigned char *dev, unsigned char *pbuf); -diff --git linux-5.8/3rdparty/rtl8812au/include/hal_btcoex.h linux-5.8/3rdparty/rtl8812au/include/hal_btcoex.h -new file mode 100644 -index 000000000..03021fee3 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/hal_btcoex.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/Hal8812PhyCfg.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/Hal8812PhyCfg.h +--- linux-5.11.4/3rdparty/rtl8812au/include/Hal8812PhyCfg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/Hal8812PhyCfg.h 2021-03-07 18:16:17.083957423 +0200 +@@ -0,0 +1,143 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++#ifndef __INC_HAL8812PHYCFG_H__ ++#define __INC_HAL8812PHYCFG_H__ ++ ++ ++/*--------------------------Define Parameters-------------------------------*/ ++#define LOOP_LIMIT 5 ++#define MAX_STALL_TIME 50 /* us */ ++#define AntennaDiversityValue 0x80 /* (Adapter->bSoftwareAntennaDiversity ? 0x00 : 0x80) */ ++#define MAX_TXPWR_IDX_NMODE_92S 63 ++#define Reset_Cnt_Limit 3 ++ ++ ++#ifdef CONFIG_PCI_HCI ++ #define MAX_AGGR_NUM 0x0B ++#else ++ #define MAX_AGGR_NUM 0x07 ++#endif /* CONFIG_PCI_HCI */ ++ ++ ++/*--------------------------Define Parameters-------------------------------*/ ++ ++/*------------------------------Define structure----------------------------*/ ++ ++ ++/* BB/RF related */ ++ ++/*------------------------------Define structure----------------------------*/ ++ ++ ++/*------------------------Export global variable----------------------------*/ ++/*------------------------Export global variable----------------------------*/ ++ ++ ++/*------------------------Export Marco Definition---------------------------*/ ++/*------------------------Export Marco Definition---------------------------*/ ++ ++ ++/*--------------------------Exported Function prototype---------------------*/ ++/* ++ * BB and RF register read/write ++ * */ ++u32 PHY_QueryBBReg8812(IN PADAPTER Adapter, ++ IN u32 RegAddr, ++ IN u32 BitMask); ++void PHY_SetBBReg8812(IN PADAPTER Adapter, ++ IN u32 RegAddr, ++ IN u32 BitMask, ++ IN u32 Data); ++u32 PHY_QueryRFReg8812(IN PADAPTER Adapter, ++ IN enum rf_path eRFPath, ++ IN u32 RegAddr, ++ IN u32 BitMask); ++void PHY_SetRFReg8812(IN PADAPTER Adapter, ++ IN enum rf_path eRFPath, ++ IN u32 RegAddr, ++ IN u32 BitMask, ++ IN u32 Data); ++ ++/* ++ * Initialization related function ++ * ++ * MAC/BB/RF HAL config */ ++int PHY_MACConfig8812(IN PADAPTER Adapter); ++int PHY_BBConfig8812(IN PADAPTER Adapter); ++void PHY_BB8812_Config_1T(IN PADAPTER Adapter); ++int PHY_RFConfig8812(IN PADAPTER Adapter); ++ ++/* RF config */ ++ ++s32 ++PHY_SwitchWirelessBand8812( ++ IN PADAPTER Adapter, ++ IN u8 Band ++); ++ ++/* ++ * BB TX Power R/W ++ * */ ++void PHY_GetTxPowerLevel8812(IN PADAPTER Adapter, OUT s32 *powerlevel); ++void PHY_SetTxPowerLevel8812(IN PADAPTER Adapter, IN u8 Channel); ++ ++BOOLEAN PHY_UpdateTxPowerDbm8812(IN PADAPTER Adapter, IN int powerInDbm); ++u8 PHY_GetTxPowerIndex_8812A( ++ IN PADAPTER pAdapter, ++ IN enum rf_path RFPath, ++ IN u8 Rate, ++ IN u8 BandWidth, ++ IN u8 Channel, ++ struct txpwr_idx_comp *tic ++); ++ ++u32 phy_get_tx_bb_swing_8812a( ++ IN PADAPTER Adapter, ++ IN BAND_TYPE Band, ++ IN enum rf_path RFPath ++); ++ ++VOID ++PHY_SetTxPowerIndex_8812A( ++ IN PADAPTER Adapter, ++ IN u32 PowerIndex, ++ IN enum rf_path RFPath, ++ IN u8 Rate ++); ++ ++/* ++ * channel switch related funciton ++ * */ ++VOID ++PHY_SetSwChnlBWMode8812( ++ IN PADAPTER Adapter, ++ IN u8 channel, ++ IN enum channel_width Bandwidth, ++ IN u8 Offset40, ++ IN u8 Offset80 ++); ++ ++/* ++ * BB/MAC/RF other monitor API ++ * */ ++ ++VOID ++phy_set_rf_path_switch_8812a( ++ IN struct dm_struct *phydm, ++ IN bool bMain ++); ++ ++/*--------------------------Exported Function prototype---------------------*/ ++#endif /* __INC_HAL8192CPHYCFG_H */ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/Hal8812PhyReg.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/Hal8812PhyReg.h +--- linux-5.11.4/3rdparty/rtl8812au/include/Hal8812PhyReg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/Hal8812PhyReg.h 2021-03-07 18:16:17.084957471 +0200 +@@ -0,0 +1,735 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++#ifndef __INC_HAL8812PHYREG_H__ ++#define __INC_HAL8812PHYREG_H__ ++/*--------------------------Define Parameters-------------------------------*/ ++/* ++ * BB-PHY register PMAC 0x100 PHY 0x800 - 0xEFF ++ * 1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF ++ * 2. 0x800/0x900/0xA00/0xC00/0xD00/0xE00 ++ * 3. RF register 0x00-2E ++ * 4. Bit Mask for BB/RF register ++ * 5. Other defintion for BB/RF R/W ++ * */ ++ ++ ++/* BB Register Definition */ ++ ++#define rCCAonSec_Jaguar 0x838 ++#define rPwed_TH_Jaguar 0x830 ++ ++/* BW and sideband setting */ ++#define rBWIndication_Jaguar 0x834 ++#define rL1PeakTH_Jaguar 0x848 ++#define rFPGA0_XA_LSSIReadBack 0x8a0 /*Tranceiver LSSI Readback*/ ++#define rRFMOD_Jaguar 0x8ac /* RF mode */ ++#define rADC_Buf_Clk_Jaguar 0x8c4 ++#define rRFECTRL_Jaguar 0x900 ++#define bRFMOD_Jaguar 0xc3 ++#define rCCK_System_Jaguar 0xa00 /* for cck sideband */ ++#define bCCK_System_Jaguar 0x10 ++ ++/* Block & Path enable */ ++#define rOFDMCCKEN_Jaguar 0x808 /* OFDM/CCK block enable */ ++#define bOFDMEN_Jaguar 0x20000000 ++#define bCCKEN_Jaguar 0x10000000 ++#define rRxPath_Jaguar 0x808 /* Rx antenna */ ++#define bRxPath_Jaguar 0xff ++#define rTxPath_Jaguar 0x80c /* Tx antenna */ ++#define bTxPath_Jaguar 0x0fffffff ++#define rCCK_RX_Jaguar 0xa04 /* for cck rx path selection */ ++#define bCCK_RX_Jaguar 0x0c000000 ++#define rVhtlen_Use_Lsig_Jaguar 0x8c3 /* Use LSIG for VHT length */ ++ ++/* RF read/write-related */ ++#define rHSSIRead_Jaguar 0x8b0 /* RF read addr */ ++#define bHSSIRead_addr_Jaguar 0xff ++#define bHSSIRead_trigger_Jaguar 0x100 ++#define rA_PIRead_Jaguar 0xd04 /* RF readback with PI */ ++#define rB_PIRead_Jaguar 0xd44 /* RF readback with PI */ ++#define rA_SIRead_Jaguar 0xd08 /* RF readback with SI */ ++#define rB_SIRead_Jaguar 0xd48 /* RF readback with SI */ ++#define rRead_data_Jaguar 0xfffff ++#define rA_LSSIWrite_Jaguar 0xc90 /* RF write addr */ ++#define rB_LSSIWrite_Jaguar 0xe90 /* RF write addr */ ++#define bLSSIWrite_data_Jaguar 0x000fffff ++#define bLSSIWrite_addr_Jaguar 0x0ff00000 ++ ++ ++ ++/* YN: mask the following register definition temporarily */ ++#define rFPGA0_XA_RFInterfaceOE 0x860 /* RF Channel switch */ ++#define rFPGA0_XB_RFInterfaceOE 0x864 ++ ++#define rFPGA0_XAB_RFInterfaceSW 0x870 /* RF Interface Software Control */ ++#define rFPGA0_XCD_RFInterfaceSW 0x874 ++ ++/* #define rFPGA0_XAB_RFParameter 0x878 */ /* RF Parameter ++ * #define rFPGA0_XCD_RFParameter 0x87c */ ++ ++/* #define rFPGA0_AnalogParameter1 0x880 */ /* Crystal cap setting RF-R/W protection for parameter4?? ++ * #define rFPGA0_AnalogParameter2 0x884 ++ * #define rFPGA0_AnalogParameter3 0x888 ++ * #define rFPGA0_AdDaClockEn 0x888 */ /* enable ad/da clock1 for dual-phy ++ * #define rFPGA0_AnalogParameter4 0x88c */ ++ ++ ++/* CCK TX scaling */ ++#define rCCK_TxFilter1_Jaguar 0xa20 ++#define bCCK_TxFilter1_C0_Jaguar 0x00ff0000 ++#define bCCK_TxFilter1_C1_Jaguar 0xff000000 ++#define rCCK_TxFilter2_Jaguar 0xa24 ++#define bCCK_TxFilter2_C2_Jaguar 0x000000ff ++#define bCCK_TxFilter2_C3_Jaguar 0x0000ff00 ++#define bCCK_TxFilter2_C4_Jaguar 0x00ff0000 ++#define bCCK_TxFilter2_C5_Jaguar 0xff000000 ++#define rCCK_TxFilter3_Jaguar 0xa28 ++#define bCCK_TxFilter3_C6_Jaguar 0x000000ff ++#define bCCK_TxFilter3_C7_Jaguar 0x0000ff00 ++ ++ ++/* YN: mask the following register definition temporarily ++ * #define rPdp_AntA 0xb00 ++ * #define rPdp_AntA_4 0xb04 ++ * #define rConfig_Pmpd_AntA 0xb28 ++ * #define rConfig_AntA 0xb68 ++ * #define rConfig_AntB 0xb6c ++ * #define rPdp_AntB 0xb70 ++ * #define rPdp_AntB_4 0xb74 ++ * #define rConfig_Pmpd_AntB 0xb98 ++ * #define rAPK 0xbd8 */ ++ ++/* RXIQC */ ++#define rA_RxIQC_AB_Jaguar 0xc10 /* RxIQ imblance matrix coeff. A & B */ ++#define rA_RxIQC_CD_Jaguar 0xc14 /* RxIQ imblance matrix coeff. C & D */ ++#define rA_TxScale_Jaguar 0xc1c /* Pah_A TX scaling factor */ ++#define rB_TxScale_Jaguar 0xe1c /* Path_B TX scaling factor */ ++#define rB_RxIQC_AB_Jaguar 0xe10 /* RxIQ imblance matrix coeff. A & B */ ++#define rB_RxIQC_CD_Jaguar 0xe14 /* RxIQ imblance matrix coeff. C & D */ ++#define b_RxIQC_AC_Jaguar 0x02ff /* bit mask for IQC matrix element A & C */ ++#define b_RxIQC_BD_Jaguar 0x02ff0000 /* bit mask for IQC matrix element A & C */ ++ ++ ++/* DIG-related */ ++#define rA_IGI_Jaguar 0xc50 /* Initial Gain for path-A */ ++#define rB_IGI_Jaguar 0xe50 /* Initial Gain for path-B */ ++#define rOFDM_FalseAlarm1_Jaguar 0xf48 /* counter for break */ ++#define rOFDM_FalseAlarm2_Jaguar 0xf4c /* counter for spoofing */ ++#define rCCK_FalseAlarm_Jaguar 0xa5c /* counter for cck false alarm */ ++#define b_FalseAlarm_Jaguar 0xffff ++#define rCCK_CCA_Jaguar 0xa08 /* cca threshold */ ++#define bCCK_CCA_Jaguar 0x00ff0000 ++ ++/* Tx Power Ttraining-related */ ++#define rA_TxPwrTraing_Jaguar 0xc54 ++#define rB_TxPwrTraing_Jaguar 0xe54 ++ ++/* Report-related */ ++#define rOFDM_ShortCFOAB_Jaguar 0xf60 ++#define rOFDM_LongCFOAB_Jaguar 0xf64 ++#define rOFDM_EndCFOAB_Jaguar 0xf70 ++#define rOFDM_AGCReport_Jaguar 0xf84 ++#define rOFDM_RxSNR_Jaguar 0xf88 ++#define rOFDM_RxEVMCSI_Jaguar 0xf8c ++#define rOFDM_SIGReport_Jaguar 0xf90 ++ ++/* Misc functions */ ++#define rEDCCA_Jaguar 0x8a4 /* EDCCA */ ++#define bEDCCA_Jaguar 0xffff ++#define rAGC_table_Jaguar 0x82c /* AGC tabel select */ ++#define bAGC_table_Jaguar 0x3 ++#define b_sel5g_Jaguar 0x1000 /* sel5g */ ++#define b_LNA_sw_Jaguar 0x8000 /* HW/WS control for LNA */ ++#define rFc_area_Jaguar 0x860 /* fc_area */ ++#define bFc_area_Jaguar 0x1ffe000 ++#define rSingleTone_ContTx_Jaguar 0x914 ++ ++/* RFE */ ++#define rA_RFE_Pinmux_Jaguar 0xcb0 /* Path_A RFE cotrol pinmux */ ++#define rB_RFE_Pinmux_Jaguar 0xeb0 /* Path_B RFE control pinmux */ ++#define rA_RFE_Inv_Jaguar 0xcb4 /* Path_A RFE cotrol */ ++#define rB_RFE_Inv_Jaguar 0xeb4 /* Path_B RFE control */ ++#define rA_RFE_Jaguar 0xcb8 /* Path_A RFE cotrol */ ++#define rB_RFE_Jaguar 0xeb8 /* Path_B RFE control */ ++#define rA_RFE_Inverse_Jaguar 0xCBC /* Path_A RFE control inverse */ ++#define rB_RFE_Inverse_Jaguar 0xEBC /* Path_B RFE control inverse */ ++#define r_ANTSEL_SW_Jaguar 0x900 /* ANTSEL SW Control */ ++#define bMask_RFEInv_Jaguar 0x3ff00000 ++#define bMask_AntselPathFollow_Jaguar 0x00030000 ++ ++/* TX AGC */ ++#define rTxAGC_A_CCK11_CCK1_JAguar 0xc20 ++#define rTxAGC_A_Ofdm18_Ofdm6_JAguar 0xc24 ++#define rTxAGC_A_Ofdm54_Ofdm24_JAguar 0xc28 ++#define rTxAGC_A_MCS3_MCS0_JAguar 0xc2c ++#define rTxAGC_A_MCS7_MCS4_JAguar 0xc30 ++#define rTxAGC_A_MCS11_MCS8_JAguar 0xc34 ++#define rTxAGC_A_MCS15_MCS12_JAguar 0xc38 ++#define rTxAGC_A_Nss1Index3_Nss1Index0_JAguar 0xc3c ++#define rTxAGC_A_Nss1Index7_Nss1Index4_JAguar 0xc40 ++#define rTxAGC_A_Nss2Index1_Nss1Index8_JAguar 0xc44 ++#define rTxAGC_A_Nss2Index5_Nss2Index2_JAguar 0xc48 ++#define rTxAGC_A_Nss2Index9_Nss2Index6_JAguar 0xc4c ++#define rTxAGC_B_CCK11_CCK1_JAguar 0xe20 ++#define rTxAGC_B_Ofdm18_Ofdm6_JAguar 0xe24 ++#define rTxAGC_B_Ofdm54_Ofdm24_JAguar 0xe28 ++#define rTxAGC_B_MCS3_MCS0_JAguar 0xe2c ++#define rTxAGC_B_MCS7_MCS4_JAguar 0xe30 ++#define rTxAGC_B_MCS11_MCS8_JAguar 0xe34 ++#define rTxAGC_B_MCS15_MCS12_JAguar 0xe38 ++#define rTxAGC_B_Nss1Index3_Nss1Index0_JAguar 0xe3c ++#define rTxAGC_B_Nss1Index7_Nss1Index4_JAguar 0xe40 ++#define rTxAGC_B_Nss2Index1_Nss1Index8_JAguar 0xe44 ++#define rTxAGC_B_Nss2Index5_Nss2Index2_JAguar 0xe48 ++#define rTxAGC_B_Nss2Index9_Nss2Index6_JAguar 0xe4c ++#define bTxAGC_byte0_Jaguar 0xff ++#define bTxAGC_byte1_Jaguar 0xff00 ++#define bTxAGC_byte2_Jaguar 0xff0000 ++#define bTxAGC_byte3_Jaguar 0xff000000 ++ ++/* IQK YN: temporaily mask this part ++ * #define rFPGA0_IQK 0xe28 ++ * #define rTx_IQK_Tone_A 0xe30 ++ * #define rRx_IQK_Tone_A 0xe34 ++ * #define rTx_IQK_PI_A 0xe38 ++ * #define rRx_IQK_PI_A 0xe3c */ ++ ++/* #define rTx_IQK 0xe40 */ ++/* #define rRx_IQK 0xe44 */ ++/* #define rIQK_AGC_Pts 0xe48 */ ++/* #define rIQK_AGC_Rsp 0xe4c */ ++/* #define rTx_IQK_Tone_B 0xe50 */ ++/* #define rRx_IQK_Tone_B 0xe54 */ ++/* #define rTx_IQK_PI_B 0xe58 */ ++/* #define rRx_IQK_PI_B 0xe5c */ ++/* #define rIQK_AGC_Cont 0xe60 */ ++ ++ ++/* AFE-related */ ++#define rA_AFEPwr1_Jaguar 0xc60 /* dynamic AFE power control */ ++#define rA_AFEPwr2_Jaguar 0xc64 /* dynamic AFE power control */ ++#define rA_Rx_WaitCCA_Tx_CCKRFON_Jaguar 0xc68 ++#define rA_Tx_CCKBBON_OFDMRFON_Jaguar 0xc6c ++#define rA_Tx_OFDMBBON_Tx2Rx_Jaguar 0xc70 ++#define rA_Tx2Tx_RXCCK_Jaguar 0xc74 ++#define rA_Rx_OFDM_WaitRIFS_Jaguar 0xc78 ++#define rA_Rx2Rx_BT_Jaguar 0xc7c ++#define rA_sleep_nav_Jaguar 0xc80 ++#define rA_pmpd_Jaguar 0xc84 ++#define rB_AFEPwr1_Jaguar 0xe60 /* dynamic AFE power control */ ++#define rB_AFEPwr2_Jaguar 0xe64 /* dynamic AFE power control */ ++#define rB_Rx_WaitCCA_Tx_CCKRFON_Jaguar 0xe68 ++#define rB_Tx_CCKBBON_OFDMRFON_Jaguar 0xe6c ++#define rB_Tx_OFDMBBON_Tx2Rx_Jaguar 0xe70 ++#define rB_Tx2Tx_RXCCK_Jaguar 0xe74 ++#define rB_Rx_OFDM_WaitRIFS_Jaguar 0xe78 ++#define rB_Rx2Rx_BT_Jaguar 0xe7c ++#define rB_sleep_nav_Jaguar 0xe80 ++#define rB_pmpd_Jaguar 0xe84 ++ ++ ++/* YN: mask these registers temporaily ++ * #define rTx_Power_Before_IQK_A 0xe94 ++ * #define rTx_Power_After_IQK_A 0xe9c */ ++ ++/* #define rRx_Power_Before_IQK_A 0xea0 */ ++/* #define rRx_Power_Before_IQK_A_2 0xea4 */ ++/* #define rRx_Power_After_IQK_A 0xea8 */ ++/* #define rRx_Power_After_IQK_A_2 0xeac */ ++ ++/* #define rTx_Power_Before_IQK_B 0xeb4 */ ++/* #define rTx_Power_After_IQK_B 0xebc */ ++ ++/* #define rRx_Power_Before_IQK_B 0xec0 */ ++/* #define rRx_Power_Before_IQK_B_2 0xec4 */ ++/* #define rRx_Power_After_IQK_B 0xec8 */ ++/* #define rRx_Power_After_IQK_B_2 0xecc */ ++ ++ ++/* RSSI Dump */ ++#define rA_RSSIDump_Jaguar 0xBF0 ++#define rB_RSSIDump_Jaguar 0xBF1 ++#define rS1_RXevmDump_Jaguar 0xBF4 ++#define rS2_RXevmDump_Jaguar 0xBF5 ++#define rA_RXsnrDump_Jaguar 0xBF6 ++#define rB_RXsnrDump_Jaguar 0xBF7 ++#define rA_CfoShortDump_Jaguar 0xBF8 ++#define rB_CfoShortDump_Jaguar 0xBFA ++#define rA_CfoLongDump_Jaguar 0xBEC ++#define rB_CfoLongDump_Jaguar 0xBEE ++ ++ ++/* RF Register ++ * */ ++#define RF_AC_Jaguar 0x00 /* */ ++#define RF_RF_Top_Jaguar 0x07 /* */ ++#define RF_TXLOK_Jaguar 0x08 /* */ ++#define RF_TXAPK_Jaguar 0x0B ++#define RF_CHNLBW_Jaguar 0x18 /* RF channel and BW switch */ ++#define RF_RCK1_Jaguar 0x1c /* */ ++#define RF_RCK2_Jaguar 0x1d ++#define RF_RCK3_Jaguar 0x1e ++#define RF_ModeTableAddr 0x30 ++#define RF_ModeTableData0 0x31 ++#define RF_ModeTableData1 0x32 ++#define RF_TxLCTank_Jaguar 0x54 ++#define RF_APK_Jaguar 0x63 ++#define RF_LCK 0xB4 ++#define RF_WeLut_Jaguar 0xEF ++ ++#define bRF_CHNLBW_MOD_AG_Jaguar 0x70300 ++#define bRF_CHNLBW_BW 0xc00 ++ ++ ++/* ++ * RL6052 Register definition ++ * */ ++#define RF_AC 0x00 /* */ ++#define RF_IPA_A 0x0C /* */ ++#define RF_TXBIAS_A 0x0D ++#define RF_BS_PA_APSET_G9_G11 0x0E ++#define RF_MODE1 0x10 /* */ ++#define RF_MODE2 0x11 /* */ ++#define RF_CHNLBW 0x18 /* RF channel and BW switch */ ++#define RF_RCK_OS 0x30 /* RF TX PA control */ ++#define RF_TXPA_G1 0x31 /* RF TX PA control */ ++#define RF_TXPA_G2 0x32 /* RF TX PA control */ ++#define RF_TXPA_G3 0x33 /* RF TX PA control */ ++#define RF_0x52 0x52 ++#define RF_WE_LUT 0xEF ++ ++#define RF_TX_GAIN_OFFSET_8812A(_val) ((abs((_val)) << 1) | (((_val) > 0) ? BIT0 : 0)) ++#define RF_TX_GAIN_OFFSET_8821A(_val) ((abs((_val)) << 1) | (((_val) > 0) ? BIT0 : 0)) ++ ++/* ++ * Bit Mask ++ * ++ * 1. Page1(0x100) */ ++#define bBBResetB 0x100 /* Useless now? */ ++#define bGlobalResetB 0x200 ++#define bOFDMTxStart 0x4 ++#define bCCKTxStart 0x8 ++#define bCRC32Debug 0x100 ++#define bPMACLoopback 0x10 ++#define bTxLSIG 0xffffff ++#define bOFDMTxRate 0xf ++#define bOFDMTxReserved 0x10 ++#define bOFDMTxLength 0x1ffe0 ++#define bOFDMTxParity 0x20000 ++#define bTxHTSIG1 0xffffff ++#define bTxHTMCSRate 0x7f ++#define bTxHTBW 0x80 ++#define bTxHTLength 0xffff00 ++#define bTxHTSIG2 0xffffff ++#define bTxHTSmoothing 0x1 ++#define bTxHTSounding 0x2 ++#define bTxHTReserved 0x4 ++#define bTxHTAggreation 0x8 ++#define bTxHTSTBC 0x30 ++#define bTxHTAdvanceCoding 0x40 ++#define bTxHTShortGI 0x80 ++#define bTxHTNumberHT_LTF 0x300 ++#define bTxHTCRC8 0x3fc00 ++#define bCounterReset 0x10000 ++#define bNumOfOFDMTx 0xffff ++#define bNumOfCCKTx 0xffff0000 ++#define bTxIdleInterval 0xffff ++#define bOFDMService 0xffff0000 ++#define bTxMACHeader 0xffffffff ++#define bTxDataInit 0xff ++#define bTxHTMode 0x100 ++#define bTxDataType 0x30000 ++#define bTxRandomSeed 0xffffffff ++#define bCCKTxPreamble 0x1 ++#define bCCKTxSFD 0xffff0000 ++#define bCCKTxSIG 0xff ++#define bCCKTxService 0xff00 ++#define bCCKLengthExt 0x8000 ++#define bCCKTxLength 0xffff0000 ++#define bCCKTxCRC16 0xffff ++#define bCCKTxStatus 0x1 ++#define bOFDMTxStatus 0x2 ++ ++ ++/* ++ * 1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF ++ * 1. Page1(0x100) ++ * */ ++#define rPMAC_Reset 0x100 ++#define rPMAC_TxStart 0x104 ++#define rPMAC_TxLegacySIG 0x108 ++#define rPMAC_TxHTSIG1 0x10c ++#define rPMAC_TxHTSIG2 0x110 ++#define rPMAC_PHYDebug 0x114 ++#define rPMAC_TxPacketNum 0x118 ++#define rPMAC_TxIdle 0x11c ++#define rPMAC_TxMACHeader0 0x120 ++#define rPMAC_TxMACHeader1 0x124 ++#define rPMAC_TxMACHeader2 0x128 ++#define rPMAC_TxMACHeader3 0x12c ++#define rPMAC_TxMACHeader4 0x130 ++#define rPMAC_TxMACHeader5 0x134 ++#define rPMAC_TxDataType 0x138 ++#define rPMAC_TxRandomSeed 0x13c ++#define rPMAC_CCKPLCPPreamble 0x140 ++#define rPMAC_CCKPLCPHeader 0x144 ++#define rPMAC_CCKCRC16 0x148 ++#define rPMAC_OFDMRxCRC32OK 0x170 ++#define rPMAC_OFDMRxCRC32Er 0x174 ++#define rPMAC_OFDMRxParityEr 0x178 ++#define rPMAC_OFDMRxCRC8Er 0x17c ++#define rPMAC_CCKCRxRC16Er 0x180 ++#define rPMAC_CCKCRxRC32Er 0x184 ++#define rPMAC_CCKCRxRC32OK 0x188 ++#define rPMAC_TxStatus 0x18c ++ ++/* ++ * 3. Page8(0x800) ++ * */ ++#define rFPGA0_RFMOD 0x800 /* RF mode & CCK TxSC */ /* RF BW Setting?? */ ++ ++#define rFPGA0_TxInfo 0x804 /* Status report?? */ ++#define rFPGA0_PSDFunction 0x808 ++#define rFPGA0_TxGainStage 0x80c /* Set TX PWR init gain? */ ++ ++#define rFPGA0_XA_HSSIParameter1 0x820 /* RF 3 wire register */ ++#define rFPGA0_XA_HSSIParameter2 0x824 ++#define rFPGA0_XB_HSSIParameter1 0x828 ++#define rFPGA0_XB_HSSIParameter2 0x82c ++ ++#define rFPGA0_XAB_SwitchControl 0x858 /* RF Channel switch */ ++#define rFPGA0_XCD_SwitchControl 0x85c ++ ++#define rFPGA0_XAB_RFParameter 0x878 /* RF Parameter */ ++#define rFPGA0_XCD_RFParameter 0x87c ++ ++#define rFPGA0_AnalogParameter1 0x880 /* Crystal cap setting RF-R/W protection for parameter4?? */ ++#define rFPGA0_AnalogParameter2 0x884 ++#define rFPGA0_AnalogParameter3 0x888 ++#define rFPGA0_AdDaClockEn 0x888 /* enable ad/da clock1 for dual-phy */ ++#define rFPGA0_AnalogParameter4 0x88c ++#define rFPGA0_XB_LSSIReadBack 0x8a4 ++#define rFPGA0_XCD_RFPara 0x8b4 ++ ++/* ++ * 4. Page9(0x900) ++ * */ ++#define rFPGA1_RFMOD 0x900 /* RF mode & OFDM TxSC */ /* RF BW Setting?? */ ++ ++#define rFPGA1_TxBlock 0x904 /* Useless now */ ++#define rFPGA1_DebugSelect 0x908 /* Useless now */ ++#define rFPGA1_TxInfo 0x90c /* Useless now */ /* Status report?? */ ++ ++/* ++ * PageA(0xA00) ++ * */ ++#define rCCK0_System 0xa00 ++#define rCCK0_AFESetting 0xa04 /* Disable init gain now */ /* Select RX path by RSSI */ ++#define rCCK0_DSPParameter2 0xa1c /* SQ threshold */ ++#define rCCK0_TxFilter1 0xa20 ++#define rCCK0_TxFilter2 0xa24 ++#define rCCK0_DebugPort 0xa28 /* debug port and Tx filter3 */ ++#define rCCK0_FalseAlarmReport 0xa2c /* 0xa2d useless now 0xa30-a4f channel report */ ++ ++/* ++ * PageB(0xB00) ++ * */ ++#define rPdp_AntA 0xb00 ++#define rPdp_AntA_4 0xb04 ++#define rConfig_Pmpd_AntA 0xb28 ++#define rConfig_AntA 0xb68 ++#define rConfig_AntB 0xb6c ++#define rPdp_AntB 0xb70 ++#define rPdp_AntB_4 0xb74 ++#define rConfig_Pmpd_AntB 0xb98 ++#define rAPK 0xbd8 ++ ++/* ++ * 6. PageC(0xC00) ++ * */ ++#define rOFDM0_LSTF 0xc00 ++ ++#define rOFDM0_TRxPathEnable 0xc04 ++#define rOFDM0_TRMuxPar 0xc08 ++#define rOFDM0_TRSWIsolation 0xc0c ++ ++#define rOFDM0_XARxAFE 0xc10 /* RxIQ DC offset, Rx digital filter, DC notch filter */ ++#define rOFDM0_XARxIQImbalance 0xc14 /* RxIQ imblance matrix */ ++#define rOFDM0_XBRxAFE 0xc18 ++#define rOFDM0_XBRxIQImbalance 0xc1c ++#define rOFDM0_XCRxAFE 0xc20 ++#define rOFDM0_XCRxIQImbalance 0xc24 ++#define rOFDM0_XDRxAFE 0xc28 ++#define rOFDM0_XDRxIQImbalance 0xc2c ++ ++#define rOFDM0_RxDetector1 0xc30 /* PD, BW & SBD */ /* DM tune init gain */ ++#define rOFDM0_RxDetector2 0xc34 /* SBD & Fame Sync. */ ++#define rOFDM0_RxDetector3 0xc38 /* Frame Sync. */ ++#define rOFDM0_RxDetector4 0xc3c /* PD, SBD, Frame Sync & Short-GI */ ++ ++#define rOFDM0_RxDSP 0xc40 /* Rx Sync Path */ ++#define rOFDM0_CFOandDAGC 0xc44 /* CFO & DAGC */ ++#define rOFDM0_CCADropThreshold 0xc48 /* CCA Drop threshold */ ++#define rOFDM0_ECCAThreshold 0xc4c /* energy CCA */ ++ ++#define rOFDM0_XAAGCCore1 0xc50 /* DIG */ ++#define rOFDM0_XAAGCCore2 0xc54 ++#define rOFDM0_XBAGCCore1 0xc58 ++#define rOFDM0_XBAGCCore2 0xc5c ++#define rOFDM0_XCAGCCore1 0xc60 ++#define rOFDM0_XCAGCCore2 0xc64 ++#define rOFDM0_XDAGCCore1 0xc68 ++#define rOFDM0_XDAGCCore2 0xc6c ++ ++#define rOFDM0_AGCParameter1 0xc70 ++#define rOFDM0_AGCParameter2 0xc74 ++#define rOFDM0_AGCRSSITable 0xc78 ++#define rOFDM0_HTSTFAGC 0xc7c ++ ++#define rOFDM0_XATxIQImbalance 0xc80 /* TX PWR TRACK and DIG */ ++#define rOFDM0_XATxAFE 0xc84 ++#define rOFDM0_XBTxIQImbalance 0xc88 ++#define rOFDM0_XBTxAFE 0xc8c ++#define rOFDM0_XCTxIQImbalance 0xc90 ++#define rOFDM0_XCTxAFE 0xc94 ++#define rOFDM0_XDTxIQImbalance 0xc98 ++#define rOFDM0_XDTxAFE 0xc9c ++ ++#define rOFDM0_RxIQExtAnta 0xca0 ++#define rOFDM0_TxCoeff1 0xca4 ++#define rOFDM0_TxCoeff2 0xca8 ++#define rOFDM0_TxCoeff3 0xcac ++#define rOFDM0_TxCoeff4 0xcb0 ++#define rOFDM0_TxCoeff5 0xcb4 ++#define rOFDM0_TxCoeff6 0xcb8 ++#define rOFDM0_RxHPParameter 0xce0 ++#define rOFDM0_TxPseudoNoiseWgt 0xce4 ++#define rOFDM0_FrameSync 0xcf0 ++#define rOFDM0_DFSReport 0xcf4 ++ ++/* ++ * 7. PageD(0xD00) ++ * */ ++#define rOFDM1_LSTF 0xd00 ++#define rOFDM1_TRxPathEnable 0xd04 ++ ++/* ++ * 8. PageE(0xE00) ++ * */ ++#define rTxAGC_A_Rate18_06 0xe00 ++#define rTxAGC_A_Rate54_24 0xe04 ++#define rTxAGC_A_CCK1_Mcs32 0xe08 ++#define rTxAGC_A_Mcs03_Mcs00 0xe10 ++#define rTxAGC_A_Mcs07_Mcs04 0xe14 ++#define rTxAGC_A_Mcs11_Mcs08 0xe18 ++#define rTxAGC_A_Mcs15_Mcs12 0xe1c ++ ++#define rTxAGC_B_Rate18_06 0x830 ++#define rTxAGC_B_Rate54_24 0x834 ++#define rTxAGC_B_CCK1_55_Mcs32 0x838 ++#define rTxAGC_B_Mcs03_Mcs00 0x83c ++#define rTxAGC_B_Mcs07_Mcs04 0x848 ++#define rTxAGC_B_Mcs11_Mcs08 0x84c ++#define rTxAGC_B_Mcs15_Mcs12 0x868 ++#define rTxAGC_B_CCK11_A_CCK2_11 0x86c ++ ++#define rFPGA0_IQK 0xe28 ++#define rTx_IQK_Tone_A 0xe30 ++#define rRx_IQK_Tone_A 0xe34 ++#define rTx_IQK_PI_A 0xe38 ++#define rRx_IQK_PI_A 0xe3c ++ ++#define rTx_IQK 0xe40 ++#define rRx_IQK 0xe44 ++#define rIQK_AGC_Pts 0xe48 ++#define rIQK_AGC_Rsp 0xe4c ++#define rTx_IQK_Tone_B 0xe50 ++#define rRx_IQK_Tone_B 0xe54 ++#define rTx_IQK_PI_B 0xe58 ++#define rRx_IQK_PI_B 0xe5c ++#define rIQK_AGC_Cont 0xe60 ++ ++#define rBlue_Tooth 0xe6c ++#define rRx_Wait_CCA 0xe70 ++#define rTx_CCK_RFON 0xe74 ++#define rTx_CCK_BBON 0xe78 ++#define rTx_OFDM_RFON 0xe7c ++#define rTx_OFDM_BBON 0xe80 ++#define rTx_To_Rx 0xe84 ++#define rTx_To_Tx 0xe88 ++#define rRx_CCK 0xe8c ++ ++#define rTx_Power_Before_IQK_A 0xe94 ++#define rTx_Power_After_IQK_A 0xe9c ++ ++#define rRx_Power_Before_IQK_A 0xea0 ++#define rRx_Power_Before_IQK_A_2 0xea4 ++#define rRx_Power_After_IQK_A 0xea8 ++#define rRx_Power_After_IQK_A_2 0xeac ++ ++#define rTx_Power_Before_IQK_B 0xeb4 ++#define rTx_Power_After_IQK_B 0xebc ++ ++#define rRx_Power_Before_IQK_B 0xec0 ++#define rRx_Power_Before_IQK_B_2 0xec4 ++#define rRx_Power_After_IQK_B 0xec8 ++#define rRx_Power_After_IQK_B_2 0xecc ++ ++#define rRx_OFDM 0xed0 ++#define rRx_Wait_RIFS 0xed4 ++#define rRx_TO_Rx 0xed8 ++#define rStandby 0xedc ++#define rSleep 0xee0 ++#define rPMPD_ANAEN 0xeec ++ ++ ++/* 2. Page8(0x800) */ ++#define bRFMOD 0x1 /* Reg 0x800 rFPGA0_RFMOD */ ++#define bJapanMode 0x2 ++#define bCCKTxSC 0x30 ++#define bCCKEn 0x1000000 ++#define bOFDMEn 0x2000000 ++#define bXBTxAGC 0xf00 /* Reg 80c rFPGA0_TxGainStage */ ++#define bXCTxAGC 0xf000 ++#define bXDTxAGC 0xf0000 ++ ++/* 4. PageA(0xA00) */ ++#define bCCKBBMode 0x3 /* Useless */ ++#define bCCKTxPowerSaving 0x80 ++#define bCCKRxPowerSaving 0x40 ++ ++#define bCCKSideBand 0x10 /* Reg 0xa00 rCCK0_System 20/40 switch */ ++ ++#define bCCKScramble 0x8 /* Useless */ ++#define bCCKAntDiversity 0x8000 ++#define bCCKCarrierRecovery 0x4000 ++#define bCCKTxRate 0x3000 ++#define bCCKDCCancel 0x0800 ++#define bCCKISICancel 0x0400 ++#define bCCKMatchFilter 0x0200 ++#define bCCKEqualizer 0x0100 ++#define bCCKPreambleDetect 0x800000 ++#define bCCKFastFalseCCA 0x400000 ++#define bCCKChEstStart 0x300000 ++#define bCCKCCACount 0x080000 ++#define bCCKcs_lim 0x070000 ++#define bCCKBistMode 0x80000000 ++#define bCCKCCAMask 0x40000000 ++#define bCCKTxDACPhase 0x4 ++#define bCCKRxADCPhase 0x20000000 /* r_rx_clk */ ++#define bCCKr_cp_mode0 0x0100 ++#define bCCKTxDCOffset 0xf0 ++#define bCCKRxDCOffset 0xf ++#define bCCKCCAMode 0xc000 ++#define bCCKFalseCS_lim 0x3f00 ++#define bCCKCS_ratio 0xc00000 ++#define bCCKCorgBit_sel 0x300000 ++#define bCCKPD_lim 0x0f0000 ++#define bCCKNewCCA 0x80000000 ++#define bCCKRxHPofIG 0x8000 ++#define bCCKRxIG 0x7f00 ++#define bCCKLNAPolarity 0x800000 ++#define bCCKRx1stGain 0x7f0000 ++#define bCCKRFExtend 0x20000000 /* CCK Rx Iinital gain polarity */ ++#define bCCKRxAGCSatLevel 0x1f000000 ++#define bCCKRxAGCSatCount 0xe0 ++#define bCCKRxRFSettle 0x1f /* AGCsamp_dly */ ++#define bCCKFixedRxAGC 0x8000 ++/* #define bCCKRxAGCFormat 0x4000 */ /* remove to HSSI register 0x824 */ ++#define bCCKAntennaPolarity 0x2000 ++#define bCCKTxFilterType 0x0c00 ++#define bCCKRxAGCReportType 0x0300 ++#define bCCKRxDAGCEn 0x80000000 ++#define bCCKRxDAGCPeriod 0x20000000 ++#define bCCKRxDAGCSatLevel 0x1f000000 ++#define bCCKTimingRecovery 0x800000 ++#define bCCKTxC0 0x3f0000 ++#define bCCKTxC1 0x3f000000 ++#define bCCKTxC2 0x3f ++#define bCCKTxC3 0x3f00 ++#define bCCKTxC4 0x3f0000 ++#define bCCKTxC5 0x3f000000 ++#define bCCKTxC6 0x3f ++#define bCCKTxC7 0x3f00 ++#define bCCKDebugPort 0xff0000 ++#define bCCKDACDebug 0x0f000000 ++#define bCCKFalseAlarmEnable 0x8000 ++#define bCCKFalseAlarmRead 0x4000 ++#define bCCKTRSSI 0x7f ++#define bCCKRxAGCReport 0xfe ++#define bCCKRxReport_AntSel 0x80000000 ++#define bCCKRxReport_MFOff 0x40000000 ++#define bCCKRxRxReport_SQLoss 0x20000000 ++#define bCCKRxReport_Pktloss 0x10000000 ++#define bCCKRxReport_Lockedbit 0x08000000 ++#define bCCKRxReport_RateError 0x04000000 ++#define bCCKRxReport_RxRate 0x03000000 ++#define bCCKRxFACounterLower 0xff ++#define bCCKRxFACounterUpper 0xff000000 ++#define bCCKRxHPAGCStart 0xe000 ++#define bCCKRxHPAGCFinal 0x1c00 ++#define bCCKRxFalseAlarmEnable 0x8000 ++#define bCCKFACounterFreeze 0x4000 ++#define bCCKTxPathSel 0x10000000 ++#define bCCKDefaultRxPath 0xc000000 ++#define bCCKOptionRxPath 0x3000000 ++ ++/* 6. PageE(0xE00) */ ++#define bSTBCEn 0x4 /* Useless */ ++#define bAntennaMapping 0x10 ++#define bNss 0x20 ++#define bCFOAntSumD 0x200 ++#define bPHYCounterReset 0x8000000 ++#define bCFOReportGet 0x4000000 ++#define bOFDMContinueTx 0x10000000 ++#define bOFDMSingleCarrier 0x20000000 ++#define bOFDMSingleTone 0x40000000 ++ ++ ++/* ++ * Other Definition ++ * */ ++ ++#define bEnable 0x1 /* Useless */ ++#define bDisable 0x0 ++ ++/* byte endable for srwrite */ ++#define bByte0 0x1 /* Useless */ ++#define bByte1 0x2 ++#define bByte2 0x4 ++#define bByte3 0x8 ++#define bWord0 0x3 ++#define bWord1 0xc ++#define bDWord 0xf ++ ++/* for PutRegsetting & GetRegSetting BitMask */ ++#define bMaskByte0 0xff /* Reg 0xc50 rOFDM0_XAAGCCore~0xC6f */ ++#define bMaskByte1 0xff00 ++#define bMaskByte2 0xff0000 ++#define bMaskByte3 0xff000000 ++#define bMaskHWord 0xffff0000 ++#define bMaskLWord 0x0000ffff ++#define bMaskDWord 0xffffffff ++#define bMaskH3Bytes 0xffffff00 ++#define bMask12Bits 0xfff ++#define bMaskH4Bits 0xf0000000 ++#define bMaskOFDM_D 0xffc00000 ++#define bMaskCCK 0x3f3f3f3f ++ ++ ++/*--------------------------Define Parameters-------------------------------*/ ++ ++ ++#endif +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/Hal8812PwrSeq.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/Hal8812PwrSeq.h +--- linux-5.11.4/3rdparty/rtl8812au/include/Hal8812PwrSeq.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/Hal8812PwrSeq.h 2021-03-07 18:16:17.084957471 +0200 +@@ -0,0 +1,208 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++ ++ ++#ifndef __HAL8812PWRSEQ_H__ ++#define __HAL8812PWRSEQ_H__ ++ ++#include "HalPwrSeqCmd.h" ++ ++/* ++ Check document WB-110628-DZ-RTL8195 (Jaguar) Power Architecture-R04.pdf ++ There are 6 HW Power States: ++ 0: POFF--Power Off ++ 1: PDN--Power Down ++ 2: CARDEMU--Card Emulation ++ 3: ACT--Active Mode ++ 4: LPS--Low Power State ++ 5: SUS--Suspend ++ ++ The transision from different states are defined below ++ TRANS_CARDEMU_TO_ACT ++ TRANS_ACT_TO_CARDEMU ++ TRANS_CARDEMU_TO_SUS ++ TRANS_SUS_TO_CARDEMU ++ TRANS_CARDEMU_TO_PDN ++ TRANS_ACT_TO_LPS ++ TRANS_LPS_TO_ACT ++ ++ TRANS_END ++*/ ++#define RTL8812_TRANS_CARDEMU_TO_ACT_STEPS 15 ++#define RTL8812_TRANS_ACT_TO_CARDEMU_STEPS 15 ++#define RTL8812_TRANS_CARDEMU_TO_SUS_STEPS 15 ++#define RTL8812_TRANS_SUS_TO_CARDEMU_STEPS 15 ++#define RTL8812_TRANS_CARDEMU_TO_PDN_STEPS 15 ++#define RTL8812_TRANS_PDN_TO_CARDEMU_STEPS 15 ++#define RTL8812_TRANS_ACT_TO_LPS_STEPS 15 ++#define RTL8812_TRANS_LPS_TO_ACT_STEPS 15 ++#define RTL8812_TRANS_END_STEPS 1 ++ ++ ++#define RTL8812_TRANS_CARDEMU_TO_ACT \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, 0},/* disable SW LPS 0x04[10]=0*/ \ ++ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT1, BIT1},/* wait till 0x04[17] = 1 power ready*/ \ ++ /*{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0}, disable HWPDN 0x04[15]=0*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3, 0},/* disable WL suspend*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/* polling until return 0*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT0, 0},/**/ \ ++ {0x0024, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT1, 0}, /* 0x24[1] Choose the type of buffer after xosc: nand*/ \ ++ {0x0028, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3, 0}, /* 0x28[33] Choose the type of buffer after xosc: nand*/ ++ ++#define RTL8812_TRANS_ACT_TO_CARDEMU \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0c00, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x04}, /* 0xc00[7:0] = 4 turn off 3-wire */ \ ++ {0x0e00, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x04}, /* 0xe00[7:0] = 4 turn off 3-wire */ \ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0}, /* 0x2[0] = 0 RESET BB, CLOSE RF */ \ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US},/*Delay 1us*/ \ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0}, /* Whole BB is reset*/ \ ++ /*{0x001F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},//0x1F[7:0] = 0 turn off RF*/ \ ++ /*{0x004E, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0},//0x4C[23] = 0x4E[7] = 0, switch DPDT_SEL_P output from register 0x65[2] */ \ ++ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x2A}, /* 0x07[7:0] = 0x28 sps pwm mode 0x2a for BT coex*/ \ ++ {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x02, 0},/*0x8[1] = 0 ANA clk = 500k */ \ ++ /*{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0 | BIT1, 0}, // 0x02[1:0] = 0 reset BB */ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1}, /*0x04[9] = 1 turn off MAC by HW state machine*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT1, 0}, /*wait till 0x04[9] = 0 polling until return 0 to disable*/ ++ ++#define RTL8812_TRANS_CARDEMU_TO_SUS \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0042, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xF0, 0xcc},\ ++ {0x0042, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xF0, 0xEC},\ ++ {0x0043, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x07},/* gpio11 input mode, gpio10~8 output mode */ \ ++ {0x0045, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00},/* gpio 0~7 output same value as input ?? */ \ ++ {0x0046, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xff},/* gpio0~7 output mode */ \ ++ {0x0047, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/* 0x47[7:0] = 00 gpio mode */ \ ++ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/* suspend option all off */ \ ++ {0x0014, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x80, BIT7},/*0x14[7] = 1 turn on ZCD */ \ ++ {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x01, BIT0},/* 0x15[0] =1 trun on ZCD */ \ ++ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x10, BIT4},/*0x23[4] = 1 hpon LDO sleep mode */ \ ++ {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x02, 0},/*0x8[1] = 0 ANA clk = 500k */ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3, BIT3}, /*0x04[11] = 2b'11 enable WL suspend for PCIe*/ ++ ++#define RTL8812_TRANS_SUS_TO_CARDEMU \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3, 0}, /*0x04[11] = 2b'01enable WL suspend*/ \ ++ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x10, 0},/*0x23[4] = 0 hpon LDO sleep mode leave */ \ ++ {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x01, 0},/* 0x15[0] =0 trun off ZCD */ \ ++ {0x0014, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x80, 0},/*0x14[7] = 0 turn off ZCD */ \ ++ {0x0046, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00},/* gpio0~7 input mode */ \ ++ {0x0043, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00},/* gpio11 input mode, gpio10~8 input mode */ ++ ++#define RTL8812_TRANS_CARDEMU_TO_CARDDIS \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ /**{0x0194, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0}, //0x194[0]=0 , disable 32K clock*/ \ ++ /**{0x0093, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x94}, //0x93 = 0x94 , 90[30] =0 enable 500k ANA clock .switch clock from 12M to 500K , 90 [26] =0 disable EEprom loader clock*/ \ ++ {0x0003, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, 0}, /*0x03[2] = 0, reset 8051*/ \ ++ {0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x05}, /*0x80 = 05h if reload fw, fill the default value of host_CPU handshake field*/ \ ++ {0x0042, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xF0, 0xcc},\ ++ {0x0042, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xF0, 0xEC},\ ++ {0x0043, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x07},/* gpio11 input mode, gpio10~8 output mode */ \ ++ {0x0045, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00},/* gpio 0~7 output same value as input ?? */ \ ++ {0x0046, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xff},/* gpio0~7 output mode */ \ ++ {0x0047, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/* 0x47[7:0] = 00 gpio mode */ \ ++ {0x0014, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x80, BIT7},/*0x14[7] = 1 turn on ZCD */ \ ++ {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x01, BIT0},/* 0x15[0] =1 trun on ZCD */ \ ++ {0x0012, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x01, 0},/*0x12[0] = 0 force PFM mode */ \ ++ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x10, BIT4},/*0x23[4] = 1 hpon LDO sleep mode */ \ ++ {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x02, 0},/*0x8[1] = 0 ANA clk = 500k */ \ ++ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07 = 0x20 , SOP option to disable BG/MB*/ \ ++ {0x001f, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0}, /*0x01f[1]=0 , disable RFC_0 control REG_RF_CTRL_8812 */ \ ++ {0x0076, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0}, /*0x076[1]=0 , disable RFC_1 control REG_OPT_CTRL_8812 +2 */ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3, BIT3}, /*0x04[11] = 2b'01 enable WL suspend*/ ++ ++#define RTL8812_TRANS_CARDDIS_TO_CARDEMU \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0012, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/*0x12[0] = 1 force PWM mode */ \ ++ {0x0014, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x80, 0},/*0x14[7] = 0 turn off ZCD */ \ ++ {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x01, 0},/* 0x15[0] =0 trun off ZCD */ \ ++ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x10, 0},/*0x23[4] = 0 hpon LDO leave sleep mode */ \ ++ {0x0046, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00},/* gpio0~7 input mode */ \ ++ {0x0043, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00},/* gpio11 input mode, gpio10~8 input mode */ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, 0}, /*0x04[10] = 0, enable SW LPS PCIE only*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3, 0}, /*0x04[11] = 2b'01enable WL suspend*/ \ ++ {0x0003, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, BIT2}, /*0x03[2] = 1, enable 8051*/ \ ++ {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/*PCIe DMA start*/ \ ++ {0x0024, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT1, BIT1}, /* 0x24[1] Choose the type of buffer after xosc: schmitt trigger*/ \ ++ {0x0028, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3, BIT3}, /* 0x28[33] Choose the type of buffer after xosc: schmitt trigger*/ ++ ++ ++#define RTL8812_TRANS_CARDEMU_TO_PDN \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, BIT7},/* 0x04[15] = 1*/ ++ ++#define RTL8812_TRANS_PDN_TO_CARDEMU \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0},/* 0x04[15] = 0*/ ++ ++#define RTL8812_TRANS_ACT_TO_LPS \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF},/*PCIe DMA stop*/ \ ++ {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x7F},/*Tx Pause*/ \ ++ {0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ ++ {0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ ++ {0x05FA, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ ++ {0x05FB, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ ++ {0x0c00, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x04}, /* 0xc00[7:0] = 4 turn off 3-wire */ \ ++ {0x0e00, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x04}, /* 0xe00[7:0] = 4 turn off 3-wire */ \ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0},/*CCK and OFDM are disabled, and clock are gated, and RF closed*/ \ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US},/*Delay 1us*/ \ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0}, /* Whole BB is reset*/ \ ++ {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x03},/*Reset MAC TRX*/ \ ++ {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0},/*check if removed later*/ \ ++ {0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, BIT5},/*Respond TxOK to scheduler*/ ++ ++ ++#define RTL8812_TRANS_LPS_TO_ACT \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, 0xFF, 0x84}, /*SDIO RPWM*/ \ ++ {0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*USB RPWM*/ \ ++ {0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*PCIe RPWM*/ \ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS}, /*Delay*/ \ ++ {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*. 0x08[4] = 0 switch TSF to 40M*/ \ ++ {0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT7, 0}, /*Polling 0x109[7]=0 TSF in 40M*/ \ ++ {0x0029, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6 | BIT7, 0}, /*. 0x29[7:6] = 2b'00 enable BB clock*/ \ ++ {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1}, /*. 0x101[1] = 1*/ \ ++ {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF}, /*. 0x100[7:0] = 0xFF enable WMAC TRX*/ \ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1 | BIT0, BIT1 | BIT0}, /*. 0x02[1:0] = 2b'11 enable BB macro*/ \ ++ {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}, /*. 0x522 = 0*/ ++ ++#define RTL8812_TRANS_END \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, 0, PWR_CMD_END, 0, 0}, ++ ++ ++extern WLAN_PWR_CFG rtl8812_power_on_flow[RTL8812_TRANS_CARDEMU_TO_ACT_STEPS + RTL8812_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8812_radio_off_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS + RTL8812_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8812_card_disable_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS + RTL8812_TRANS_CARDEMU_TO_PDN_STEPS + RTL8812_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8812_card_enable_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS + RTL8812_TRANS_CARDEMU_TO_PDN_STEPS + RTL8812_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8812_suspend_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS + RTL8812_TRANS_CARDEMU_TO_SUS_STEPS + RTL8812_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8812_resume_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS + RTL8812_TRANS_CARDEMU_TO_SUS_STEPS + RTL8812_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8812_hwpdn_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS + RTL8812_TRANS_CARDEMU_TO_PDN_STEPS + RTL8812_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8812_enter_lps_flow[RTL8812_TRANS_ACT_TO_LPS_STEPS + RTL8812_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8812_leave_lps_flow[RTL8812_TRANS_LPS_TO_ACT_STEPS + RTL8812_TRANS_END_STEPS]; ++ ++#endif /* __HAL8812PWRSEQ_H__ */ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/Hal8814PhyCfg.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/Hal8814PhyCfg.h +--- linux-5.11.4/3rdparty/rtl8812au/include/Hal8814PhyCfg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/Hal8814PhyCfg.h 2021-03-07 18:16:17.084957471 +0200 +@@ -0,0 +1,264 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++#ifndef __INC_HAL8814PHYCFG_H__ ++#define __INC_HAL8814PHYCFG_H__ ++ ++ ++/*--------------------------Define Parameters-------------------------------*/ ++#define LOOP_LIMIT 5 ++#define MAX_STALL_TIME 50 /* us */ ++#define AntennaDiversityValue 0x80 /* (Adapter->bSoftwareAntennaDiversity ? 0x00 : 0x80) */ ++#define MAX_TXPWR_IDX_NMODE_92S 63 ++#define Reset_Cnt_Limit 3 ++ ++ ++#ifdef CONFIG_PCI_HCI ++ #define MAX_AGGR_NUM 0x0B ++#else ++ #define MAX_AGGR_NUM 0x07 ++#endif /* CONFIG_PCI_HCI */ ++ ++ ++/*--------------------------Define Parameters-------------------------------*/ ++ ++/*------------------------------Define structure----------------------------*/ ++ ++ ++/* BB/RF related */ ++ ++#define SIC_ENABLE 0 ++ ++/*------------------------------Define structure----------------------------*/ ++ ++ ++/*------------------------Export global variable----------------------------*/ ++/*------------------------Export global variable----------------------------*/ ++ ++ ++/*------------------------Export Marco Definition---------------------------*/ ++/*------------------------Export Marco Definition---------------------------*/ ++ ++ ++/*--------------------------Exported Function prototype---------------------*/ ++/* 1. BB register R/W API */ ++ ++extern u32 ++PHY_QueryBBReg8814A(IN PADAPTER Adapter, ++ IN u32 RegAddr, ++ IN u32 BitMask); ++ ++ ++VOID ++PHY_SetBBReg8814A(IN PADAPTER Adapter, ++ IN u32 RegAddr, ++ IN u32 BitMask, ++ IN u32 Data); ++ ++ ++extern u32 ++PHY_QueryRFReg8814A(IN PADAPTER Adapter, ++ IN enum rf_path eRFPath, ++ IN u32 RegAddr, ++ IN u32 BitMask); ++ ++ ++void ++PHY_SetRFReg8814A(IN PADAPTER Adapter, ++ IN enum rf_path eRFPath, ++ IN u32 RegAddr, ++ IN u32 BitMask, ++ IN u32 Data); ++ ++/* 1 3. Initial BB/RF config by reading MAC/BB/RF txt. */ ++s32 ++phy_BB8814A_Config_ParaFile( ++ IN PADAPTER Adapter ++); ++ ++VOID ++PHY_ConfigBB_8814A( ++ IN PADAPTER Adapter ++); ++ ++ ++VOID ++phy_ADC_CLK_8814A( ++ IN PADAPTER Adapter ++); ++ ++s32 ++PHY_RFConfig8814A( ++ IN PADAPTER Adapter ++); ++ ++/* ++ * RF Power setting ++ * ++ * BOOLEAN PHY_SetRFPowerState8814A(PADAPTER Adapter, rt_rf_power_state eRFPowerState); */ ++ ++/* 1 5. Tx Power setting API */ ++ ++VOID ++PHY_GetTxPowerLevel8814( ++ IN PADAPTER Adapter, ++ OUT ps4Byte powerlevel ++); ++ ++VOID ++PHY_SetTxPowerLevel8814( ++ IN PADAPTER Adapter, ++ IN u8 Channel ++); ++ ++u8 ++phy_get_tx_power_index_8814a( ++ IN PADAPTER Adapter, ++ IN enum rf_path RFPath, ++ IN u8 Rate, ++ IN enum channel_width BandWidth, ++ IN u8 Channel ++); ++ ++u8 ++PHY_GetTxPowerIndex8814A( ++ IN PADAPTER Adapter, ++ IN enum rf_path RFPath, ++ IN u8 Rate, ++ IN u8 BandWidth, ++ IN u8 Channel, ++ struct txpwr_idx_comp *tic ++); ++ ++VOID ++PHY_SetTxPowerIndex_8814A( ++ IN PADAPTER Adapter, ++ IN u32 PowerIndex, ++ IN enum rf_path RFPath, ++ IN u8 Rate ++); ++ ++ ++BOOLEAN ++PHY_UpdateTxPowerDbm8814A( ++ IN PADAPTER Adapter, ++ IN s4Byte powerInDbm ++); ++ ++ ++u32 ++PHY_GetTxBBSwing_8814A( ++ IN PADAPTER Adapter, ++ IN BAND_TYPE Band, ++ IN enum rf_path RFPath ++); ++ ++ ++ ++/* 1 6. Channel setting API */ ++#if 0 ++VOID ++PHY_SwChnlTimerCallback8814A( ++ IN struct timer_list *p_timer ++); ++#endif ++VOID ++PHY_SwChnlWorkItemCallback8814A( ++ IN PVOID pContext ++); ++ ++ ++VOID ++HAL_HandleSwChnl8814A( ++ IN PADAPTER pAdapter, ++ IN u8 channel ++); ++ ++VOID ++PHY_SwChnlSynchronously8814A(IN PADAPTER pAdapter, ++ IN u8 channel); ++ ++VOID ++PHY_SwChnlAndSetBWModeCallback8814A(IN PVOID pContext); ++ ++ ++VOID ++PHY_HandleSwChnlAndSetBW8814A( ++ IN PADAPTER Adapter, ++ IN BOOLEAN bSwitchChannel, ++ IN BOOLEAN bSetBandWidth, ++ IN u8 ChannelNum, ++ IN enum channel_width ChnlWidth, ++ IN u8 ChnlOffsetOf40MHz, ++ IN u8 ChnlOffsetOf80MHz, ++ IN u8 CenterFrequencyIndex1 ++); ++ ++ ++BOOLEAN ++PHY_QueryRFPathSwitch_8814A(IN PADAPTER pAdapter); ++ ++ ++ ++#if (USE_WORKITEM) ++VOID ++RtCheckForHangWorkItemCallback8814A( ++ IN PVOID pContext ++); ++#endif ++ ++BOOLEAN ++SetAntennaConfig8814A( ++ IN PADAPTER Adapter, ++ IN u8 DefaultAnt ++); ++ ++VOID ++PHY_SetRFEReg8814A( ++ IN PADAPTER Adapter, ++ IN BOOLEAN bInit, ++ IN u8 Band ++); ++ ++ ++s32 ++PHY_SwitchWirelessBand8814A( ++ IN PADAPTER Adapter, ++ IN u8 Band ++); ++ ++VOID ++PHY_SetIO_8814A( ++ PADAPTER pAdapter ++); ++ ++VOID ++PHY_SetSwChnlBWMode8814( ++ IN PADAPTER Adapter, ++ IN u8 channel, ++ IN enum channel_width Bandwidth, ++ IN u8 Offset40, ++ IN u8 Offset80 ++); ++ ++s32 PHY_MACConfig8814(PADAPTER Adapter); ++int PHY_BBConfig8814(PADAPTER Adapter); ++VOID PHY_Set_SecCCATH_by_RXANT_8814A(PADAPTER pAdapter, u4Byte ulAntennaRx); ++ ++ ++ ++/*--------------------------Exported Function prototype---------------------*/ ++ ++/*--------------------------Exported Function prototype---------------------*/ ++#endif /* __INC_HAL8192CPHYCFG_H */ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/Hal8814PhyReg.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/Hal8814PhyReg.h +--- linux-5.11.4/3rdparty/rtl8812au/include/Hal8814PhyReg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/Hal8814PhyReg.h 2021-03-07 18:16:17.084957471 +0200 +@@ -0,0 +1,863 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++#ifndef __INC_HAL8814PHYREG_H__ ++#define __INC_HAL8814PHYREG_H__ ++/*--------------------------Define Parameters-------------------------------*/ ++/* ++ * BB-PHY register PMAC 0x100 PHY 0x800 - 0xEFF ++ * 1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF ++ * 2. 0x800/0x900/0xA00/0xC00/0xD00/0xE00 ++ * 3. RF register 0x00-2E ++ * 4. Bit Mask for BB/RF register ++ * 5. Other defintion for BB/RF R/W ++ * */ ++ ++ ++/* BB Register Definition */ ++ ++#define rCCAonSec_Jaguar 0x838 ++#define rPwed_TH_Jaguar 0x830 ++#define rL1_Weight_Jaguar 0x840 ++#define r_L1_SBD_start_time 0x844 ++ ++/* BW and sideband setting */ ++#define rBWIndication_Jaguar 0x834 ++#define rL1PeakTH_Jaguar 0x848 ++#define rRFMOD_Jaguar 0x8ac /* RF mode */ ++#define rADC_Buf_Clk_Jaguar 0x8c4 ++#define rADC_Buf_40_Clk_Jaguar2 0x8c8 ++#define rRFECTRL_Jaguar 0x900 ++#define bRFMOD_Jaguar 0xc3 ++#define rCCK_System_Jaguar 0xa00 /* for cck sideband */ ++#define bCCK_System_Jaguar 0x10 ++ ++/* Block & Path enable */ ++#define rOFDMCCKEN_Jaguar 0x808 /* OFDM/CCK block enable */ ++#define bOFDMEN_Jaguar 0x20000000 ++#define bCCKEN_Jaguar 0x10000000 ++#define rRxPath_Jaguar 0x808 /* Rx antenna */ ++#define bRxPath_Jaguar 0xff ++#define rTxPath_Jaguar 0x80c /* Tx antenna */ ++#define bTxPath_Jaguar 0x0fffffff ++#define rCCK_RX_Jaguar 0xa04 /* for cck rx path selection */ ++#define bCCK_RX_Jaguar 0x0c000000 ++#define rVhtlen_Use_Lsig_Jaguar 0x8c3 /* Use LSIG for VHT length */ ++ ++#define rRxPath_Jaguar2 0xa04 /* Rx antenna */ ++#define rTxAnt_1Nsts_Jaguar2 0x93c /* Tx antenna for 1Nsts */ ++#define rTxAnt_23Nsts_Jaguar2 0x940 /* Tx antenna for 2Nsts and 3Nsts */ ++ ++ ++/* RF read/write-related */ ++#define rHSSIRead_Jaguar 0x8b0 /* RF read addr */ ++#define bHSSIRead_addr_Jaguar 0xff ++#define bHSSIRead_trigger_Jaguar 0x100 ++#define rA_PIRead_Jaguar 0xd04 /* RF readback with PI */ ++#define rB_PIRead_Jaguar 0xd44 /* RF readback with PI */ ++#define rA_SIRead_Jaguar 0xd08 /* RF readback with SI */ ++#define rB_SIRead_Jaguar 0xd48 /* RF readback with SI */ ++#define rRead_data_Jaguar 0xfffff ++#define rA_LSSIWrite_Jaguar 0xc90 /* RF write addr */ ++#define rB_LSSIWrite_Jaguar 0xe90 /* RF write addr */ ++#define bLSSIWrite_data_Jaguar 0x000fffff ++#define bLSSIWrite_addr_Jaguar 0x0ff00000 ++ ++#define rC_PIRead_Jaguar2 0xd84 /* RF readback with PI */ ++#define rD_PIRead_Jaguar2 0xdC4 /* RF readback with PI */ ++#define rC_SIRead_Jaguar2 0xd88 /* RF readback with SI */ ++#define rD_SIRead_Jaguar2 0xdC8 /* RF readback with SI */ ++#define rC_LSSIWrite_Jaguar2 0x1890 /* RF write addr */ ++#define rD_LSSIWrite_Jaguar2 0x1A90 /* RF write addr */ ++ ++ ++/* YN: mask the following register definition temporarily */ ++#define rFPGA0_XA_RFInterfaceOE 0x860 /* RF Channel switch */ ++#define rFPGA0_XB_RFInterfaceOE 0x864 ++ ++#define rFPGA0_XAB_RFInterfaceSW 0x870 /* RF Interface Software Control */ ++#define rFPGA0_XCD_RFInterfaceSW 0x874 ++ ++/* #define rFPGA0_XAB_RFParameter 0x878 */ /* RF Parameter ++ * #define rFPGA0_XCD_RFParameter 0x87c */ ++ ++/* #define rFPGA0_AnalogParameter1 0x880 */ /* Crystal cap setting RF-R/W protection for parameter4?? ++ * #define rFPGA0_AnalogParameter2 0x884 ++ * #define rFPGA0_AnalogParameter3 0x888 ++ * #define rFPGA0_AdDaClockEn 0x888 */ /* enable ad/da clock1 for dual-phy ++ * #define rFPGA0_AnalogParameter4 0x88c */ ++ ++ ++/* CCK TX scaling */ ++#define rCCK_TxFilter1_Jaguar 0xa20 ++#define bCCK_TxFilter1_C0_Jaguar 0x00ff0000 ++#define bCCK_TxFilter1_C1_Jaguar 0xff000000 ++#define rCCK_TxFilter2_Jaguar 0xa24 ++#define bCCK_TxFilter2_C2_Jaguar 0x000000ff ++#define bCCK_TxFilter2_C3_Jaguar 0x0000ff00 ++#define bCCK_TxFilter2_C4_Jaguar 0x00ff0000 ++#define bCCK_TxFilter2_C5_Jaguar 0xff000000 ++#define rCCK_TxFilter3_Jaguar 0xa28 ++#define bCCK_TxFilter3_C6_Jaguar 0x000000ff ++#define bCCK_TxFilter3_C7_Jaguar 0x0000ff00 ++/* NBI & CSI Mask setting */ ++#define rCSI_Mask_Setting1_Jaguar 0x874 ++#define rCSI_Fix_Mask0_Jaguar 0x880 ++#define rCSI_Fix_Mask1_Jaguar 0x884 ++#define rCSI_Fix_Mask2_Jaguar 0x888 ++#define rCSI_Fix_Mask3_Jaguar 0x88c ++#define rCSI_Fix_Mask4_Jaguar 0x890 ++#define rCSI_Fix_Mask5_Jaguar 0x894 ++#define rCSI_Fix_Mask6_Jaguar 0x898 ++#define rCSI_Fix_Mask7_Jaguar 0x89c ++#define rNBI_Setting_Jaguar 0x87c ++ ++ ++/* YN: mask the following register definition temporarily ++ * #define rPdp_AntA 0xb00 ++ * #define rPdp_AntA_4 0xb04 ++ * #define rConfig_Pmpd_AntA 0xb28 ++ * #define rConfig_AntA 0xb68 ++ * #define rConfig_AntB 0xb6c ++ * #define rPdp_AntB 0xb70 ++ * #define rPdp_AntB_4 0xb74 ++ * #define rConfig_Pmpd_AntB 0xb98 ++ * #define rAPK 0xbd8 */ ++ ++/* RXIQC */ ++#define rA_RxIQC_AB_Jaguar 0xc10 /* RxIQ imblance matrix coeff. A & B */ ++#define rA_RxIQC_CD_Jaguar 0xc14 /* RxIQ imblance matrix coeff. C & D */ ++#define rA_TxScale_Jaguar 0xc1c /* Pah_A TX scaling factor */ ++#define rB_TxScale_Jaguar 0xe1c /* Path_B TX scaling factor */ ++#define rB_RxIQC_AB_Jaguar 0xe10 /* RxIQ imblance matrix coeff. A & B */ ++#define rB_RxIQC_CD_Jaguar 0xe14 /* RxIQ imblance matrix coeff. C & D */ ++#define b_RxIQC_AC_Jaguar 0x02ff /* bit mask for IQC matrix element A & C */ ++#define b_RxIQC_BD_Jaguar 0x02ff0000 /* bit mask for IQC matrix element A & C */ ++ ++#define rC_TxScale_Jaguar2 0x181c /* Pah_C TX scaling factor */ ++#define rD_TxScale_Jaguar2 0x1A1c /* Path_D TX scaling factor */ ++#define rRF_TxGainOffset 0x55 ++ ++/* DIG-related */ ++#define rA_IGI_Jaguar 0xc50 /* Initial Gain for path-A */ ++#define rB_IGI_Jaguar 0xe50 /* Initial Gain for path-B */ ++#define rC_IGI_Jaguar2 0x1850 /* Initial Gain for path-C */ ++#define rD_IGI_Jaguar2 0x1A50 /* Initial Gain for path-D */ ++ ++#define rOFDM_FalseAlarm1_Jaguar 0xf48 /* counter for break */ ++#define rOFDM_FalseAlarm2_Jaguar 0xf4c /* counter for spoofing */ ++#define rCCK_FalseAlarm_Jaguar 0xa5c /* counter for cck false alarm */ ++#define b_FalseAlarm_Jaguar 0xffff ++#define rCCK_CCA_Jaguar 0xa08 /* cca threshold */ ++#define bCCK_CCA_Jaguar 0x00ff0000 ++ ++/* Tx Power Ttraining-related */ ++#define rA_TxPwrTraing_Jaguar 0xc54 ++#define rB_TxPwrTraing_Jaguar 0xe54 ++ ++/* Report-related */ ++#define rOFDM_ShortCFOAB_Jaguar 0xf60 ++#define rOFDM_LongCFOAB_Jaguar 0xf64 ++#define rOFDM_EndCFOAB_Jaguar 0xf70 ++#define rOFDM_AGCReport_Jaguar 0xf84 ++#define rOFDM_RxSNR_Jaguar 0xf88 ++#define rOFDM_RxEVMCSI_Jaguar 0xf8c ++#define rOFDM_SIGReport_Jaguar 0xf90 ++ ++/* Misc functions */ ++#define rEDCCA_Jaguar 0x8a4 /* EDCCA */ ++#define bEDCCA_Jaguar 0xffff ++#define rAGC_table_Jaguar 0x82c /* AGC tabel select */ ++#define bAGC_table_Jaguar 0x3 ++#define b_sel5g_Jaguar 0x1000 /* sel5g */ ++#define b_LNA_sw_Jaguar 0x8000 /* HW/WS control for LNA */ ++#define rFc_area_Jaguar 0x860 /* fc_area */ ++#define bFc_area_Jaguar 0x1ffe000 ++#define rSingleTone_ContTx_Jaguar 0x914 ++ ++#define rAGC_table_Jaguar2 0x958 /* AGC tabel select */ ++#define rDMA_trigger_Jaguar2 0x95C /* ADC sample mode */ ++ ++ ++/* RFE */ ++#define rA_RFE_Pinmux_Jaguar 0xcb0 /* Path_A RFE cotrol pinmux */ ++#define rB_RFE_Pinmux_Jaguar 0xeb0 /* Path_B RFE control pinmux */ ++#define rA_RFE_Inv_Jaguar 0xcb4 /* Path_A RFE cotrol */ ++#define rB_RFE_Inv_Jaguar 0xeb4 /* Path_B RFE control */ ++#define rA_RFE_Jaguar 0xcb8 /* Path_A RFE cotrol */ ++#define rB_RFE_Jaguar 0xeb8 /* Path_B RFE control */ ++#define rA_RFE_Inverse_Jaguar 0xCBC /* Path_A RFE control inverse */ ++#define rB_RFE_Inverse_Jaguar 0xEBC /* Path_B RFE control inverse */ ++#define r_ANTSEL_SW_Jaguar 0x900 /* ANTSEL SW Control */ ++#define bMask_RFEInv_Jaguar 0x3ff00000 ++#define bMask_AntselPathFollow_Jaguar 0x00030000 ++ ++#define rC_RFE_Pinmux_Jaguar 0x18B4 /* Path_C RFE cotrol pinmux */ ++#define rD_RFE_Pinmux_Jaguar 0x1AB4 /* Path_D RFE cotrol pinmux */ ++#define rA_RFE_Sel_Jaguar2 0x1990 ++ ++ ++ ++/* TX AGC */ ++#define rTxAGC_A_CCK11_CCK1_JAguar 0xc20 ++#define rTxAGC_A_Ofdm18_Ofdm6_JAguar 0xc24 ++#define rTxAGC_A_Ofdm54_Ofdm24_JAguar 0xc28 ++#define rTxAGC_A_MCS3_MCS0_JAguar 0xc2c ++#define rTxAGC_A_MCS7_MCS4_JAguar 0xc30 ++#define rTxAGC_A_MCS11_MCS8_JAguar 0xc34 ++#define rTxAGC_A_MCS15_MCS12_JAguar 0xc38 ++#define rTxAGC_A_Nss1Index3_Nss1Index0_JAguar 0xc3c ++#define rTxAGC_A_Nss1Index7_Nss1Index4_JAguar 0xc40 ++#define rTxAGC_A_Nss2Index1_Nss1Index8_JAguar 0xc44 ++#define rTxAGC_A_Nss2Index5_Nss2Index2_JAguar 0xc48 ++#define rTxAGC_A_Nss2Index9_Nss2Index6_JAguar 0xc4c ++#define rTxAGC_B_CCK11_CCK1_JAguar 0xe20 ++#define rTxAGC_B_Ofdm18_Ofdm6_JAguar 0xe24 ++#define rTxAGC_B_Ofdm54_Ofdm24_JAguar 0xe28 ++#define rTxAGC_B_MCS3_MCS0_JAguar 0xe2c ++#define rTxAGC_B_MCS7_MCS4_JAguar 0xe30 ++#define rTxAGC_B_MCS11_MCS8_JAguar 0xe34 ++#define rTxAGC_B_MCS15_MCS12_JAguar 0xe38 ++#define rTxAGC_B_Nss1Index3_Nss1Index0_JAguar 0xe3c ++#define rTxAGC_B_Nss1Index7_Nss1Index4_JAguar 0xe40 ++#define rTxAGC_B_Nss2Index1_Nss1Index8_JAguar 0xe44 ++#define rTxAGC_B_Nss2Index5_Nss2Index2_JAguar 0xe48 ++#define rTxAGC_B_Nss2Index9_Nss2Index6_JAguar 0xe4c ++#define bTxAGC_byte0_Jaguar 0xff ++#define bTxAGC_byte1_Jaguar 0xff00 ++#define bTxAGC_byte2_Jaguar 0xff0000 ++#define bTxAGC_byte3_Jaguar 0xff000000 ++ ++ ++/* TX AGC */ ++#define rTxAGC_A_CCK11_CCK1_Jaguar2 0xc20 ++#define rTxAGC_A_Ofdm18_Ofdm6_Jaguar2 0xc24 ++#define rTxAGC_A_Ofdm54_Ofdm24_Jaguar2 0xc28 ++#define rTxAGC_A_MCS3_MCS0_Jaguar2 0xc2c ++#define rTxAGC_A_MCS7_MCS4_Jaguar2 0xc30 ++#define rTxAGC_A_MCS11_MCS8_Jaguar2 0xc34 ++#define rTxAGC_A_MCS15_MCS12_Jaguar2 0xc38 ++#define rTxAGC_A_MCS19_MCS16_Jaguar2 0xcd8 ++#define rTxAGC_A_MCS23_MCS20_Jaguar2 0xcdc ++#define rTxAGC_A_Nss1Index3_Nss1Index0_Jaguar2 0xc3c ++#define rTxAGC_A_Nss1Index7_Nss1Index4_Jaguar2 0xc40 ++#define rTxAGC_A_Nss2Index1_Nss1Index8_Jaguar2 0xc44 ++#define rTxAGC_A_Nss2Index5_Nss2Index2_Jaguar2 0xc48 ++#define rTxAGC_A_Nss2Index9_Nss2Index6_Jaguar2 0xc4c ++#define rTxAGC_A_Nss3Index3_Nss3Index0_Jaguar2 0xce0 ++#define rTxAGC_A_Nss3Index7_Nss3Index4_Jaguar2 0xce4 ++#define rTxAGC_A_Nss3Index9_Nss3Index8_Jaguar2 0xce8 ++#define rTxAGC_B_CCK11_CCK1_Jaguar2 0xe20 ++#define rTxAGC_B_Ofdm18_Ofdm6_Jaguar2 0xe24 ++#define rTxAGC_B_Ofdm54_Ofdm24_Jaguar2 0xe28 ++#define rTxAGC_B_MCS3_MCS0_Jaguar2 0xe2c ++#define rTxAGC_B_MCS7_MCS4_Jaguar2 0xe30 ++#define rTxAGC_B_MCS11_MCS8_Jaguar2 0xe34 ++#define rTxAGC_B_MCS15_MCS12_Jaguar2 0xe38 ++#define rTxAGC_B_MCS19_MCS16_Jaguar2 0xed8 ++#define rTxAGC_B_MCS23_MCS20_Jaguar2 0xedc ++#define rTxAGC_B_Nss1Index3_Nss1Index0_Jaguar2 0xe3c ++#define rTxAGC_B_Nss1Index7_Nss1Index4_Jaguar2 0xe40 ++#define rTxAGC_B_Nss2Index1_Nss1Index8_Jaguar2 0xe44 ++#define rTxAGC_B_Nss2Index5_Nss2Index2_Jaguar2 0xe48 ++#define rTxAGC_B_Nss2Index9_Nss2Index6_Jaguar2 0xe4c ++#define rTxAGC_B_Nss3Index3_Nss3Index0_Jaguar2 0xee0 ++#define rTxAGC_B_Nss3Index7_Nss3Index4_Jaguar2 0xee4 ++#define rTxAGC_B_Nss3Index9_Nss3Index8_Jaguar2 0xee8 ++#define rTxAGC_C_CCK11_CCK1_Jaguar2 0x1820 ++#define rTxAGC_C_Ofdm18_Ofdm6_Jaguar2 0x1824 ++#define rTxAGC_C_Ofdm54_Ofdm24_Jaguar2 0x1828 ++#define rTxAGC_C_MCS3_MCS0_Jaguar2 0x182c ++#define rTxAGC_C_MCS7_MCS4_Jaguar2 0x1830 ++#define rTxAGC_C_MCS11_MCS8_Jaguar2 0x1834 ++#define rTxAGC_C_MCS15_MCS12_Jaguar2 0x1838 ++#define rTxAGC_C_MCS19_MCS16_Jaguar2 0x18d8 ++#define rTxAGC_C_MCS23_MCS20_Jaguar2 0x18dc ++#define rTxAGC_C_Nss1Index3_Nss1Index0_Jaguar2 0x183c ++#define rTxAGC_C_Nss1Index7_Nss1Index4_Jaguar2 0x1840 ++#define rTxAGC_C_Nss2Index1_Nss1Index8_Jaguar2 0x1844 ++#define rTxAGC_C_Nss2Index5_Nss2Index2_Jaguar2 0x1848 ++#define rTxAGC_C_Nss2Index9_Nss2Index6_Jaguar2 0x184c ++#define rTxAGC_C_Nss3Index3_Nss3Index0_Jaguar2 0x18e0 ++#define rTxAGC_C_Nss3Index7_Nss3Index4_Jaguar2 0x18e4 ++#define rTxAGC_C_Nss3Index9_Nss3Index8_Jaguar2 0x18e8 ++#define rTxAGC_D_CCK11_CCK1_Jaguar2 0x1a20 ++#define rTxAGC_D_Ofdm18_Ofdm6_Jaguar2 0x1a24 ++#define rTxAGC_D_Ofdm54_Ofdm24_Jaguar2 0x1a28 ++#define rTxAGC_D_MCS3_MCS0_Jaguar2 0x1a2c ++#define rTxAGC_D_MCS7_MCS4_Jaguar2 0x1a30 ++#define rTxAGC_D_MCS11_MCS8_Jaguar2 0x1a34 ++#define rTxAGC_D_MCS15_MCS12_Jaguar2 0x1a38 ++#define rTxAGC_D_MCS19_MCS16_Jaguar2 0x1ad8 ++#define rTxAGC_D_MCS23_MCS20_Jaguar2 0x1adc ++#define rTxAGC_D_Nss1Index3_Nss1Index0_Jaguar2 0x1a3c ++#define rTxAGC_D_Nss1Index7_Nss1Index4_Jaguar2 0x1a40 ++#define rTxAGC_D_Nss2Index1_Nss1Index8_Jaguar2 0x1a44 ++#define rTxAGC_D_Nss2Index5_Nss2Index2_Jaguar2 0x1a48 ++#define rTxAGC_D_Nss2Index9_Nss2Index6_Jaguar2 0x1a4c ++#define rTxAGC_D_Nss3Index3_Nss3Index0_Jaguar2 0x1ae0 ++#define rTxAGC_D_Nss3Index7_Nss3Index4_Jaguar2 0x1ae4 ++#define rTxAGC_D_Nss3Index9_Nss3Index8_Jaguar2 0x1ae8 ++/* IQK YN: temporaily mask this part ++ * #define rFPGA0_IQK 0xe28 ++ * #define rTx_IQK_Tone_A 0xe30 ++ * #define rRx_IQK_Tone_A 0xe34 ++ * #define rTx_IQK_PI_A 0xe38 ++ * #define rRx_IQK_PI_A 0xe3c */ ++ ++/* #define rTx_IQK 0xe40 */ ++/* #define rRx_IQK 0xe44 */ ++/* #define rIQK_AGC_Pts 0xe48 */ ++/* #define rIQK_AGC_Rsp 0xe4c */ ++/* #define rTx_IQK_Tone_B 0xe50 */ ++/* #define rRx_IQK_Tone_B 0xe54 */ ++/* #define rTx_IQK_PI_B 0xe58 */ ++/* #define rRx_IQK_PI_B 0xe5c */ ++/* #define rIQK_AGC_Cont 0xe60 */ ++ ++ ++/* AFE-related */ ++#define rA_AFEPwr1_Jaguar 0xc60 /* dynamic AFE power control */ ++#define rA_AFEPwr2_Jaguar 0xc64 /* dynamic AFE power control */ ++#define rA_Rx_WaitCCA_Tx_CCKRFON_Jaguar 0xc68 ++#define rA_Tx_CCKBBON_OFDMRFON_Jaguar 0xc6c ++#define rA_Tx_OFDMBBON_Tx2Rx_Jaguar 0xc70 ++#define rA_Tx2Tx_RXCCK_Jaguar 0xc74 ++#define rA_Rx_OFDM_WaitRIFS_Jaguar 0xc78 ++#define rA_Rx2Rx_BT_Jaguar 0xc7c ++#define rA_sleep_nav_Jaguar 0xc80 ++#define rA_pmpd_Jaguar 0xc84 ++#define rB_AFEPwr1_Jaguar 0xe60 /* dynamic AFE power control */ ++#define rB_AFEPwr2_Jaguar 0xe64 /* dynamic AFE power control */ ++#define rB_Rx_WaitCCA_Tx_CCKRFON_Jaguar 0xe68 ++#define rB_Tx_CCKBBON_OFDMRFON_Jaguar 0xe6c ++#define rB_Tx_OFDMBBON_Tx2Rx_Jaguar 0xe70 ++#define rB_Tx2Tx_RXCCK_Jaguar 0xe74 ++#define rB_Rx_OFDM_WaitRIFS_Jaguar 0xe78 ++#define rB_Rx2Rx_BT_Jaguar 0xe7c ++#define rB_sleep_nav_Jaguar 0xe80 ++#define rB_pmpd_Jaguar 0xe84 ++ ++ ++/* YN: mask these registers temporaily ++ * #define rTx_Power_Before_IQK_A 0xe94 ++ * #define rTx_Power_After_IQK_A 0xe9c */ ++ ++/* #define rRx_Power_Before_IQK_A 0xea0 */ ++/* #define rRx_Power_Before_IQK_A_2 0xea4 */ ++/* #define rRx_Power_After_IQK_A 0xea8 */ ++/* #define rRx_Power_After_IQK_A_2 0xeac */ ++ ++/* #define rTx_Power_Before_IQK_B 0xeb4 */ ++/* #define rTx_Power_After_IQK_B 0xebc */ ++ ++/* #define rRx_Power_Before_IQK_B 0xec0 */ ++/* #define rRx_Power_Before_IQK_B_2 0xec4 */ ++/* #define rRx_Power_After_IQK_B 0xec8 */ ++/* #define rRx_Power_After_IQK_B_2 0xecc */ ++ ++ ++/* RSSI Dump */ ++#define rA_RSSIDump_Jaguar 0xBF0 ++#define rB_RSSIDump_Jaguar 0xBF1 ++#define rS1_RXevmDump_Jaguar 0xBF4 ++#define rS2_RXevmDump_Jaguar 0xBF5 ++#define rA_RXsnrDump_Jaguar 0xBF6 ++#define rB_RXsnrDump_Jaguar 0xBF7 ++#define rA_CfoShortDump_Jaguar 0xBF8 ++#define rB_CfoShortDump_Jaguar 0xBFA ++#define rA_CfoLongDump_Jaguar 0xBEC ++#define rB_CfoLongDump_Jaguar 0xBEE ++ ++ ++/* RF Register ++ * */ ++#define RF_AC_Jaguar 0x00 /* */ ++#define RF_RF_Top_Jaguar 0x07 /* */ ++#define RF_TXLOK_Jaguar 0x08 /* */ ++#define RF_TXAPK_Jaguar 0x0B ++#define RF_CHNLBW_Jaguar 0x18 /* RF channel and BW switch */ ++#define RF_RCK1_Jaguar 0x1c /* */ ++#define RF_RCK2_Jaguar 0x1d ++#define RF_RCK3_Jaguar 0x1e ++#define RF_ModeTableAddr 0x30 ++#define RF_ModeTableData0 0x31 ++#define RF_ModeTableData1 0x32 ++#define RF_TxLCTank_Jaguar 0x54 ++#define RF_APK_Jaguar 0x63 ++#define RF_LCK 0xB4 ++#define RF_WeLut_Jaguar 0xEF ++ ++#define bRF_CHNLBW_MOD_AG_Jaguar 0x70300 ++#define bRF_CHNLBW_BW 0xc00 ++ ++ ++/* ++ * RL6052 Register definition ++ * */ ++#define RF_AC 0x00 /* */ ++#define RF_IPA_A 0x0C /* */ ++#define RF_TXBIAS_A 0x0D ++#define RF_BS_PA_APSET_G9_G11 0x0E ++#define RF_MODE1 0x10 /* */ ++#define RF_MODE2 0x11 /* */ ++#define RF_CHNLBW 0x18 /* RF channel and BW switch */ ++#define RF_RCK_OS 0x30 /* RF TX PA control */ ++#define RF_TXPA_G1 0x31 /* RF TX PA control */ ++#define RF_TXPA_G2 0x32 /* RF TX PA control */ ++#define RF_TXPA_G3 0x33 /* RF TX PA control */ ++#define RF_0x52 0x52 ++#define RF_WE_LUT 0xEF ++ ++/* ++ * Bit Mask ++ * ++ * 1. Page1(0x100) */ ++#define bBBResetB 0x100 /* Useless now? */ ++#define bGlobalResetB 0x200 ++#define bOFDMTxStart 0x4 ++#define bCCKTxStart 0x8 ++#define bCRC32Debug 0x100 ++#define bPMACLoopback 0x10 ++#define bTxLSIG 0xffffff ++#define bOFDMTxRate 0xf ++#define bOFDMTxReserved 0x10 ++#define bOFDMTxLength 0x1ffe0 ++#define bOFDMTxParity 0x20000 ++#define bTxHTSIG1 0xffffff ++#define bTxHTMCSRate 0x7f ++#define bTxHTBW 0x80 ++#define bTxHTLength 0xffff00 ++#define bTxHTSIG2 0xffffff ++#define bTxHTSmoothing 0x1 ++#define bTxHTSounding 0x2 ++#define bTxHTReserved 0x4 ++#define bTxHTAggreation 0x8 ++#define bTxHTSTBC 0x30 ++#define bTxHTAdvanceCoding 0x40 ++#define bTxHTShortGI 0x80 ++#define bTxHTNumberHT_LTF 0x300 ++#define bTxHTCRC8 0x3fc00 ++#define bCounterReset 0x10000 ++#define bNumOfOFDMTx 0xffff ++#define bNumOfCCKTx 0xffff0000 ++#define bTxIdleInterval 0xffff ++#define bOFDMService 0xffff0000 ++#define bTxMACHeader 0xffffffff ++#define bTxDataInit 0xff ++#define bTxHTMode 0x100 ++#define bTxDataType 0x30000 ++#define bTxRandomSeed 0xffffffff ++#define bCCKTxPreamble 0x1 ++#define bCCKTxSFD 0xffff0000 ++#define bCCKTxSIG 0xff ++#define bCCKTxService 0xff00 ++#define bCCKLengthExt 0x8000 ++#define bCCKTxLength 0xffff0000 ++#define bCCKTxCRC16 0xffff ++#define bCCKTxStatus 0x1 ++#define bOFDMTxStatus 0x2 ++ ++ ++/* ++ * 1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF ++ * 1. Page1(0x100) ++ * */ ++#define rPMAC_Reset 0x100 ++#define rPMAC_TxStart 0x104 ++#define rPMAC_TxLegacySIG 0x108 ++#define rPMAC_TxHTSIG1 0x10c ++#define rPMAC_TxHTSIG2 0x110 ++#define rPMAC_PHYDebug 0x114 ++#define rPMAC_TxPacketNum 0x118 ++#define rPMAC_TxIdle 0x11c ++#define rPMAC_TxMACHeader0 0x120 ++#define rPMAC_TxMACHeader1 0x124 ++#define rPMAC_TxMACHeader2 0x128 ++#define rPMAC_TxMACHeader3 0x12c ++#define rPMAC_TxMACHeader4 0x130 ++#define rPMAC_TxMACHeader5 0x134 ++#define rPMAC_TxDataType 0x138 ++#define rPMAC_TxRandomSeed 0x13c ++#define rPMAC_CCKPLCPPreamble 0x140 ++#define rPMAC_CCKPLCPHeader 0x144 ++#define rPMAC_CCKCRC16 0x148 ++#define rPMAC_OFDMRxCRC32OK 0x170 ++#define rPMAC_OFDMRxCRC32Er 0x174 ++#define rPMAC_OFDMRxParityEr 0x178 ++#define rPMAC_OFDMRxCRC8Er 0x17c ++#define rPMAC_CCKCRxRC16Er 0x180 ++#define rPMAC_CCKCRxRC32Er 0x184 ++#define rPMAC_CCKCRxRC32OK 0x188 ++#define rPMAC_TxStatus 0x18c ++ ++/* ++ * 3. Page8(0x800) ++ * */ ++#define rFPGA0_RFMOD 0x800 /* RF mode & CCK TxSC */ /* RF BW Setting?? */ ++ ++#define rFPGA0_TxInfo 0x804 /* Status report?? */ ++#define rFPGA0_PSDFunction 0x808 ++#define rFPGA0_TxGainStage 0x80c /* Set TX PWR init gain? */ ++ ++#define rFPGA0_XA_HSSIParameter1 0x820 /* RF 3 wire register */ ++#define rFPGA0_XA_HSSIParameter2 0x824 ++#define rFPGA0_XB_HSSIParameter1 0x828 ++#define rFPGA0_XB_HSSIParameter2 0x82c ++ ++#define rFPGA0_XA_LSSIParameter 0x840 ++#define rFPGA0_XB_LSSIParameter 0x844 ++ ++#define rFPGA0_XAB_SwitchControl 0x858 /* RF Channel switch */ ++#define rFPGA0_XCD_SwitchControl 0x85c ++ ++#define rFPGA0_XAB_RFParameter 0x878 /* RF Parameter */ ++#define rFPGA0_XCD_RFParameter 0x87c ++ ++#define rFPGA0_AnalogParameter1 0x880 /* Crystal cap setting RF-R/W protection for parameter4?? */ ++#define rFPGA0_AnalogParameter2 0x884 ++#define rFPGA0_AnalogParameter3 0x888 ++#define rFPGA0_AdDaClockEn 0x888 /* enable ad/da clock1 for dual-phy */ ++#define rFPGA0_AnalogParameter4 0x88c ++ ++#define rFPGA0_XA_LSSIReadBack 0x8a0 /* Tranceiver LSSI Readback */ ++#define rFPGA0_XB_LSSIReadBack 0x8a4 ++#define rFPGA0_XC_LSSIReadBack 0x8a8 ++#define rFPGA0_XD_LSSIReadBack 0x8ac ++ ++#define rFPGA0_XCD_RFPara 0x8b4 ++#define rFPGA0_PSDReport 0x8b4 /* Useless now */ ++#define TransceiverA_HSPI_Readback 0x8b8 /* Transceiver A HSPI Readback */ ++#define TransceiverB_HSPI_Readback 0x8bc /* Transceiver B HSPI Readback */ ++#define rFPGA0_XAB_RFInterfaceRB 0x8e0 /* Useless now */ /* RF Interface Readback Value */ ++#define rFPGA0_XCD_RFInterfaceRB 0x8e4 /* Useless now */ ++ ++/* ++ * 4. Page9(0x900) ++ * */ ++#define rFPGA1_RFMOD 0x900 /* RF mode & OFDM TxSC */ /* RF BW Setting?? */ ++#define REG_BB_TX_PATH_SEL_1_8814A 0x93c ++#define REG_BB_TX_PATH_SEL_2_8814A 0x940 ++#define rFPGA1_TxBlock 0x904 /* Useless now */ ++#define rFPGA1_DebugSelect 0x908 /* Useless now */ ++#define rFPGA1_TxInfo 0x90c /* Useless now */ /* Status report?? */ ++/*Page 19 for TxBF*/ ++#define REG_BB_TXBF_ANT_SET_BF1_8814A 0x19ac ++#define REG_BB_TXBF_ANT_SET_BF0_8814A 0x19b4 ++/* ++ * PageA(0xA00) ++ * */ ++#define rCCK0_System 0xa00 ++#define rCCK0_AFESetting 0xa04 /* Disable init gain now */ /* Select RX path by RSSI */ ++#define rCCK0_DSPParameter2 0xa1c /* SQ threshold */ ++#define rCCK0_TxFilter1 0xa20 ++#define rCCK0_TxFilter2 0xa24 ++#define rCCK0_DebugPort 0xa28 /* debug port and Tx filter3 */ ++#define rCCK0_FalseAlarmReport 0xa2c /* 0xa2d useless now 0xa30-a4f channel report */ ++ ++/* ++ * PageB(0xB00) ++ * */ ++#define rPdp_AntA 0xb00 ++#define rPdp_AntA_4 0xb04 ++#define rConfig_Pmpd_AntA 0xb28 ++#define rConfig_AntA 0xb68 ++#define rConfig_AntB 0xb6c ++#define rPdp_AntB 0xb70 ++#define rPdp_AntB_4 0xb74 ++#define rConfig_Pmpd_AntB 0xb98 ++#define rAPK 0xbd8 ++ ++/* ++ * 6. PageC(0xC00) ++ * */ ++#define rOFDM0_LSTF 0xc00 ++ ++#define rOFDM0_TRxPathEnable 0xc04 ++#define rOFDM0_TRMuxPar 0xc08 ++#define rOFDM0_TRSWIsolation 0xc0c ++ ++#define rOFDM0_XARxAFE 0xc10 /* RxIQ DC offset, Rx digital filter, DC notch filter */ ++#define rOFDM0_XARxIQImbalance 0xc14 /* RxIQ imblance matrix */ ++#define rOFDM0_XBRxAFE 0xc18 ++#define rOFDM0_XBRxIQImbalance 0xc1c ++#define rOFDM0_XCRxAFE 0xc20 ++#define rOFDM0_XCRxIQImbalance 0xc24 ++#define rOFDM0_XDRxAFE 0xc28 ++#define rOFDM0_XDRxIQImbalance 0xc2c ++ ++#define rOFDM0_RxDetector1 0xc30 /* PD, BW & SBD */ /* DM tune init gain */ ++#define rOFDM0_RxDetector2 0xc34 /* SBD & Fame Sync. */ ++#define rOFDM0_RxDetector3 0xc38 /* Frame Sync. */ ++#define rOFDM0_RxDetector4 0xc3c /* PD, SBD, Frame Sync & Short-GI */ ++ ++#define rOFDM0_RxDSP 0xc40 /* Rx Sync Path */ ++#define rOFDM0_CFOandDAGC 0xc44 /* CFO & DAGC */ ++#define rOFDM0_CCADropThreshold 0xc48 /* CCA Drop threshold */ ++#define rOFDM0_ECCAThreshold 0xc4c /* energy CCA */ ++ ++#define rOFDM0_XAAGCCore1 0xc50 /* DIG */ ++#define rOFDM0_XAAGCCore2 0xc54 ++#define rOFDM0_XBAGCCore1 0xc58 ++#define rOFDM0_XBAGCCore2 0xc5c ++#define rOFDM0_XCAGCCore1 0xc60 ++#define rOFDM0_XCAGCCore2 0xc64 ++#define rOFDM0_XDAGCCore1 0xc68 ++#define rOFDM0_XDAGCCore2 0xc6c ++ ++#define rOFDM0_AGCParameter1 0xc70 ++#define rOFDM0_AGCParameter2 0xc74 ++#define rOFDM0_AGCRSSITable 0xc78 ++#define rOFDM0_HTSTFAGC 0xc7c ++ ++#define rOFDM0_XATxIQImbalance 0xc80 /* TX PWR TRACK and DIG */ ++#define rOFDM0_XATxAFE 0xc84 ++#define rOFDM0_XBTxIQImbalance 0xc88 ++#define rOFDM0_XBTxAFE 0xc8c ++#define rOFDM0_XCTxIQImbalance 0xc90 ++#define rOFDM0_XCTxAFE 0xc94 ++#define rOFDM0_XDTxIQImbalance 0xc98 ++#define rOFDM0_XDTxAFE 0xc9c ++ ++#define rOFDM0_RxIQExtAnta 0xca0 ++#define rOFDM0_TxCoeff1 0xca4 ++#define rOFDM0_TxCoeff2 0xca8 ++#define rOFDM0_TxCoeff3 0xcac ++#define rOFDM0_TxCoeff4 0xcb0 ++#define rOFDM0_TxCoeff5 0xcb4 ++#define rOFDM0_TxCoeff6 0xcb8 ++#define rOFDM0_RxHPParameter 0xce0 ++#define rOFDM0_TxPseudoNoiseWgt 0xce4 ++#define rOFDM0_FrameSync 0xcf0 ++#define rOFDM0_DFSReport 0xcf4 ++ ++/* ++ * 7. PageD(0xD00) ++ * */ ++#define rOFDM1_LSTF 0xd00 ++#define rOFDM1_TRxPathEnable 0xd04 ++ ++/* ++ * 8. PageE(0xE00) ++ * */ ++#define rTxAGC_A_Rate18_06 0xe00 ++#define rTxAGC_A_Rate54_24 0xe04 ++#define rTxAGC_A_CCK1_Mcs32 0xe08 ++#define rTxAGC_A_Mcs03_Mcs00 0xe10 ++#define rTxAGC_A_Mcs07_Mcs04 0xe14 ++#define rTxAGC_A_Mcs11_Mcs08 0xe18 ++#define rTxAGC_A_Mcs15_Mcs12 0xe1c ++ ++#define rTxAGC_B_Rate18_06 0x830 ++#define rTxAGC_B_Rate54_24 0x834 ++#define rTxAGC_B_CCK1_55_Mcs32 0x838 ++#define rTxAGC_B_Mcs03_Mcs00 0x83c ++#define rTxAGC_B_Mcs07_Mcs04 0x848 ++#define rTxAGC_B_Mcs11_Mcs08 0x84c ++#define rTxAGC_B_Mcs15_Mcs12 0x868 ++#define rTxAGC_B_CCK11_A_CCK2_11 0x86c ++ ++#define rFPGA0_IQK 0xe28 ++#define rTx_IQK_Tone_A 0xe30 ++#define rRx_IQK_Tone_A 0xe34 ++#define rTx_IQK_PI_A 0xe38 ++#define rRx_IQK_PI_A 0xe3c ++ ++#define rTx_IQK 0xe40 ++#define rRx_IQK 0xe44 ++#define rIQK_AGC_Pts 0xe48 ++#define rIQK_AGC_Rsp 0xe4c ++#define rTx_IQK_Tone_B 0xe50 ++#define rRx_IQK_Tone_B 0xe54 ++#define rTx_IQK_PI_B 0xe58 ++#define rRx_IQK_PI_B 0xe5c ++#define rIQK_AGC_Cont 0xe60 ++ ++#define rBlue_Tooth 0xe6c ++#define rRx_Wait_CCA 0xe70 ++#define rTx_CCK_RFON 0xe74 ++#define rTx_CCK_BBON 0xe78 ++#define rTx_OFDM_RFON 0xe7c ++#define rTx_OFDM_BBON 0xe80 ++#define rTx_To_Rx 0xe84 ++#define rTx_To_Tx 0xe88 ++#define rRx_CCK 0xe8c ++ ++#define rTx_Power_Before_IQK_A 0xe94 ++#define rTx_Power_After_IQK_A 0xe9c ++ ++#define rRx_Power_Before_IQK_A 0xea0 ++#define rRx_Power_Before_IQK_A_2 0xea4 ++#define rRx_Power_After_IQK_A 0xea8 ++#define rRx_Power_After_IQK_A_2 0xeac ++ ++#define rTx_Power_Before_IQK_B 0xeb4 ++#define rTx_Power_After_IQK_B 0xebc ++ ++#define rRx_Power_Before_IQK_B 0xec0 ++#define rRx_Power_Before_IQK_B_2 0xec4 ++#define rRx_Power_After_IQK_B 0xec8 ++#define rRx_Power_After_IQK_B_2 0xecc ++ ++#define rRx_OFDM 0xed0 ++#define rRx_Wait_RIFS 0xed4 ++#define rRx_TO_Rx 0xed8 ++#define rStandby 0xedc ++#define rSleep 0xee0 ++#define rPMPD_ANAEN 0xeec ++ ++ ++/* 2. Page8(0x800) */ ++#define bRFMOD 0x1 /* Reg 0x800 rFPGA0_RFMOD */ ++#define bJapanMode 0x2 ++#define bCCKTxSC 0x30 ++#define bCCKEn 0x1000000 ++#define bOFDMEn 0x2000000 ++#define bXBTxAGC 0xf00 /* Reg 80c rFPGA0_TxGainStage */ ++#define bXCTxAGC 0xf000 ++#define bXDTxAGC 0xf0000 ++ ++/* 4. PageA(0xA00) */ ++#define bCCKBBMode 0x3 /* Useless */ ++#define bCCKTxPowerSaving 0x80 ++#define bCCKRxPowerSaving 0x40 ++ ++#define bCCKSideBand 0x10 /* Reg 0xa00 rCCK0_System 20/40 switch */ ++ ++#define bCCKScramble 0x8 /* Useless */ ++#define bCCKAntDiversity 0x8000 ++#define bCCKCarrierRecovery 0x4000 ++#define bCCKTxRate 0x3000 ++#define bCCKDCCancel 0x0800 ++#define bCCKISICancel 0x0400 ++#define bCCKMatchFilter 0x0200 ++#define bCCKEqualizer 0x0100 ++#define bCCKPreambleDetect 0x800000 ++#define bCCKFastFalseCCA 0x400000 ++#define bCCKChEstStart 0x300000 ++#define bCCKCCACount 0x080000 ++#define bCCKcs_lim 0x070000 ++#define bCCKBistMode 0x80000000 ++#define bCCKCCAMask 0x40000000 ++#define bCCKTxDACPhase 0x4 ++#define bCCKRxADCPhase 0x20000000 /* r_rx_clk */ ++#define bCCKr_cp_mode0 0x0100 ++#define bCCKTxDCOffset 0xf0 ++#define bCCKRxDCOffset 0xf ++#define bCCKCCAMode 0xc000 ++#define bCCKFalseCS_lim 0x3f00 ++#define bCCKCS_ratio 0xc00000 ++#define bCCKCorgBit_sel 0x300000 ++#define bCCKPD_lim 0x0f0000 ++#define bCCKNewCCA 0x80000000 ++#define bCCKRxHPofIG 0x8000 ++#define bCCKRxIG 0x7f00 ++#define bCCKLNAPolarity 0x800000 ++#define bCCKRx1stGain 0x7f0000 ++#define bCCKRFExtend 0x20000000 /* CCK Rx Iinital gain polarity */ ++#define bCCKRxAGCSatLevel 0x1f000000 ++#define bCCKRxAGCSatCount 0xe0 ++#define bCCKRxRFSettle 0x1f /* AGCsamp_dly */ ++#define bCCKFixedRxAGC 0x8000 ++/* #define bCCKRxAGCFormat 0x4000 */ /* remove to HSSI register 0x824 */ ++#define bCCKAntennaPolarity 0x2000 ++#define bCCKTxFilterType 0x0c00 ++#define bCCKRxAGCReportType 0x0300 ++#define bCCKRxDAGCEn 0x80000000 ++#define bCCKRxDAGCPeriod 0x20000000 ++#define bCCKRxDAGCSatLevel 0x1f000000 ++#define bCCKTimingRecovery 0x800000 ++#define bCCKTxC0 0x3f0000 ++#define bCCKTxC1 0x3f000000 ++#define bCCKTxC2 0x3f ++#define bCCKTxC3 0x3f00 ++#define bCCKTxC4 0x3f0000 ++#define bCCKTxC5 0x3f000000 ++#define bCCKTxC6 0x3f ++#define bCCKTxC7 0x3f00 ++#define bCCKDebugPort 0xff0000 ++#define bCCKDACDebug 0x0f000000 ++#define bCCKFalseAlarmEnable 0x8000 ++#define bCCKFalseAlarmRead 0x4000 ++#define bCCKTRSSI 0x7f ++#define bCCKRxAGCReport 0xfe ++#define bCCKRxReport_AntSel 0x80000000 ++#define bCCKRxReport_MFOff 0x40000000 ++#define bCCKRxRxReport_SQLoss 0x20000000 ++#define bCCKRxReport_Pktloss 0x10000000 ++#define bCCKRxReport_Lockedbit 0x08000000 ++#define bCCKRxReport_RateError 0x04000000 ++#define bCCKRxReport_RxRate 0x03000000 ++#define bCCKRxFACounterLower 0xff ++#define bCCKRxFACounterUpper 0xff000000 ++#define bCCKRxHPAGCStart 0xe000 ++#define bCCKRxHPAGCFinal 0x1c00 ++#define bCCKRxFalseAlarmEnable 0x8000 ++#define bCCKFACounterFreeze 0x4000 ++#define bCCKTxPathSel 0x10000000 ++#define bCCKDefaultRxPath 0xc000000 ++#define bCCKOptionRxPath 0x3000000 ++ ++#define RF_T_METER_88E 0x42 ++ ++/* 6. PageE(0xE00) */ ++#define bSTBCEn 0x4 /* Useless */ ++#define bAntennaMapping 0x10 ++#define bNss 0x20 ++#define bCFOAntSumD 0x200 ++#define bPHYCounterReset 0x8000000 ++#define bCFOReportGet 0x4000000 ++#define bOFDMContinueTx 0x10000000 ++#define bOFDMSingleCarrier 0x20000000 ++#define bOFDMSingleTone 0x40000000 ++ ++ ++/* ++ * Other Definition ++ * */ ++ ++#define bEnable 0x1 /* Useless */ ++#define bDisable 0x0 ++ ++/* byte endable for srwrite */ ++#define bByte0 0x1 /* Useless */ ++#define bByte1 0x2 ++#define bByte2 0x4 ++#define bByte3 0x8 ++#define bWord0 0x3 ++#define bWord1 0xc ++#define bDWord 0xf ++ ++/* for PutRegsetting & GetRegSetting BitMask */ ++#define bMaskByte0 0xff /* Reg 0xc50 rOFDM0_XAAGCCore~0xC6f */ ++#define bMaskByte1 0xff00 ++#define bMaskByte2 0xff0000 ++#define bMaskByte3 0xff000000 ++#define bMaskHWord 0xffff0000 ++#define bMaskLWord 0x0000ffff ++#define bMaskDWord 0xffffffff ++#define bMaskH3Bytes 0xffffff00 ++#define bMask12Bits 0xfff ++#define bMaskH4Bits 0xf0000000 ++#define bMaskOFDM_D 0xffc00000 ++#define bMaskCCK 0x3f3f3f3f ++#define bMask7bits 0x7f ++#define bMaskByte2HighNibble 0x00f00000 ++#define bMaskByte3LowNibble 0x0f000000 ++#define bMaskL3Bytes 0x00ffffff ++ ++/*--------------------------Define Parameters-------------------------------*/ ++ ++ ++#endif +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/Hal8814PwrSeq.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/Hal8814PwrSeq.h +--- linux-5.11.4/3rdparty/rtl8812au/include/Hal8814PwrSeq.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/Hal8814PwrSeq.h 2021-03-07 18:16:17.084957471 +0200 +@@ -0,0 +1,231 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++ ++ ++#ifndef __HAL8814PWRSEQ_H__ ++#define __HAL8814PWRSEQ_H__ ++ ++#include "HalPwrSeqCmd.h" ++ ++/* ++ Check document WB-110628-DZ-RTL8195 (Jaguar) Power Architecture-R04.pdf ++ There are 6 HW Power States: ++ 0: POFF--Power Off ++ 1: PDN--Power Down ++ 2: CARDEMU--Card Emulation ++ 3: ACT--Active Mode ++ 4: LPS--Low Power State ++ 5: SUS--Suspend ++ ++ The transision from different states are defined below ++ TRANS_CARDEMU_TO_ACT ++ TRANS_ACT_TO_CARDEMU ++ TRANS_CARDEMU_TO_SUS ++ TRANS_SUS_TO_CARDEMU ++ TRANS_CARDEMU_TO_PDN ++ TRANS_ACT_TO_LPS ++ TRANS_LPS_TO_ACT ++ ++ TRANS_END ++*/ ++#define RTL8814A_TRANS_CARDEMU_TO_ACT_STEPS 16 ++#define RTL8814A_TRANS_ACT_TO_CARDEMU_STEPS 20 ++#define RTL8814A_TRANS_CARDEMU_TO_SUS_STEPS 17 ++#define RTL8814A_TRANS_SUS_TO_CARDEMU_STEPS 15 ++#define RTL8814A_TRANS_CARDEMU_TO_PDN_STEPS 17 ++#define RTL8814A_TRANS_PDN_TO_CARDEMU_STEPS 16 ++#define RTL8814A_TRANS_ACT_TO_LPS_STEPS 20 ++#define RTL8814A_TRANS_LPS_TO_ACT_STEPS 15 ++#define RTL8814A_TRANS_END_STEPS 1 ++ ++ ++#define RTL8814A_TRANS_CARDEMU_TO_ACT \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, 0},/* disable SW LPS 0x04[10]=0*/ \ ++ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT1, BIT1},/* wait till 0x04[17] = 1 power ready*/ \ ++ {0x002B, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0}, /* ??0x28[24]=1, enable pll phase select*/ \ ++ {0x0015, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, (BIT3 | BIT2 | BIT1), (BIT3 | BIT2 | BIT1)},/* 0x14[11:9]=3'b111, OCP current threshold = 1.5A */ \ ++ {0x002D, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x0E, 0x08},/* 0x2C[11:9]=3'b100, select lpf R3 */ \ ++ {0x002D, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x70, 0x50},/* 0x2C[14:12]=3'b101, select lpf Rs*/ \ ++ {0x007B, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6, BIT6},/* 0x78[30]=1'b1, SDM order select*/ \ ++ /*{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0}, */ /* disable HWPDN 0x04[15]=0*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3, 0},/* disable WL suspend*/ \ ++ {0x00F0, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0},/* */ \ ++ {0x0081, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x30, 0x20},/* */ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/* polling until return 0*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT0, 0},/**/ ++ ++#define RTL8814A_TRANS_ACT_TO_CARDEMU \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0c00, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x04}, /* 0xc00[7:0] = 4 turn off 3-wire */ \ ++ {0x0e00, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x04}, /* 0xe00[7:0] = 4 turn off 3-wire */ \ ++ {0x0002, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0}, /* 0x2[0] = 0 RESET BB, CLOSE RF */ \ ++ {0x0002, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US}, /*Delay 1us*/ \ ++ {0x0002, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0}, /* Whole BB is reset*/ \ ++ {0x1002, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0}, /* 0x2[0] = 0 RESET BB, CLOSE RF */ \ ++ {0x0002, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US}, /*Delay 1us*/ \ ++ {0x1002, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0}, /* Whole BB is reset*/ \ ++ {0x001F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}, /*0x1F[7:0] = 0 turn off RF*/ \ ++ /*{0x004E, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0},*/ /*0x4C[23] = 0x4E[7] = 0, switch DPDT_SEL_P output from register 0x65[2] */ \ ++ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x28}, /* 0x07[7:0] = 0x28 sps pwm mode 0x2a for BT coex*/ \ ++ {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x02, 0}, /*0x8[1] = 0 ANA clk = 500k */ \ ++ /*{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0 | BIT1, 0},*/ /* 0x02[1:0] = 0 reset BB */ \ ++ {0x0066, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0}, /*0x66[7]=0, disable ckreq for gpio7 output SUS */ \ ++ {0x0041, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*0x41[4]=0, disable sic for gpio7 output SUS */ \ ++ {0x0042, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0}, /*0x42[1]=0, disable ckout for gpio7 output SUS */ \ ++ {0x004e, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, BIT5}, /*0x4E[5]=1, disable LED2 for gpio7 output SUS */ \ ++ {0x0041, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0}, /*0x41[0]=0, disable uart for gpio7 output SUS */ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1}, /*0x04[9] = 1 turn off MAC by HW state machine*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT1, 0}, /*wait till 0x04[9] = 0 polling until return 0 to disable*/ ++ ++#define RTL8814A_TRANS_CARDEMU_TO_SUS \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0061, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x0F, 0x0c},\ ++ {0x0061, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x0F, 0x0E},\ ++ {0x0062, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x0F, 0x07},/* gpio11 input mode, gpio10~8 output mode */ \ ++ {0x0045, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00},/* gpio 0~7 output same value as input ?? */ \ ++ {0x0046, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xff},/* gpio0~7 output mode */ \ ++ {0x0047, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/* 0x47[7:0] = 00 gpio mode */ \ ++ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/* suspend option all off */ \ ++ {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, BIT5},/*0x14[13] = 1 turn on ZCD */ \ ++ {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6, BIT6},/* 0x14[14] =1 trun on ZCD */ \ ++ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, BIT4},/*0x23[4] = 1 hpon LDO sleep mode */ \ ++ {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0},/*0x8[1] = 0 ANA clk = 500k */ \ ++ {0x0091, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xA0, 0xA0}, /* 0x91[7]=1 0x91[5]=1 , disable sps, ldo sleep mode */ \ ++ {0x0070, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3, BIT3}, /* 0x70[3]=1 enable mainbias polling */ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3, BIT3}, /*0x04[11] = 1 enable WL suspend */ ++ ++#define RTL8814A_TRANS_SUS_TO_CARDEMU \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3, 0}, /*0x04[11] = 0 enable WL suspend*/ \ ++ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x10, 0},/*0x23[4] = 0 hpon LDO sleep mode leave */ \ ++ {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6, 0},/* 0x14[14] =0 trun off ZCD */ \ ++ {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, 0},/*0x14[13] = 0 turn off ZCD */ \ ++ {0x0046, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00},/* gpio0~7 input mode */ \ ++ {0x0062, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00},/* gpio11 input mode, gpio10~8 input mode */ ++ ++#define RTL8814A_TRANS_CARDEMU_TO_CARDDIS \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ /**{0x0194, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0}, //0x194[0]=0 , disable 32K clock*/ \ ++ /**{0x0093, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x94}, //0x93 = 0x94 , 90[30] =0 enable 500k ANA clock .switch clock from 12M to 500K , 90 [26] =0 disable EEprom loader clock*/ \ ++ {0x0003, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, 0}, /*0x03[2] = 0, reset 3081*/ \ ++ {0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x01}, /*0x80 = 05h if reload fw, fill the default value of host_CPU handshake field*/ \ ++ {0x0081, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x30}, /*0x80 = 05h if reload fw, fill the default value of host_CPU handshake field*/ \ ++ /*{0x0042, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xF0, 0xcc},*/ \ ++ /*{0x0042, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xF0, 0xEC},*/ \ ++ /*{0x0043, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x07},*/ /* gpio11 input mode, gpio10~8 output mode */ \ ++ {0x0045, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00},/* gpio 0~7 output same value as input ?? */ \ ++ {0x0046, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xff},/* gpio0~7 output mode */ \ ++ {0x0047, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/* 0x47[7:0] = 00 gpio mode */ \ ++ {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6, BIT6},/* 0x15[6] =1 trun on ZCD output */ \ ++ {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, BIT5},/*0x15[5] = 1 turn on ZCD */ \ ++ {0x0012, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6, 0},/*0x12[6] = 0 force PFM mode */ \ ++ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, BIT4},/*0x23[4] = 1 hpon LDO sleep mode */ \ ++ {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0},/*0x8[1] = 0 ANA clk = 500k */ \ ++ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07 = 0x20 , SOP option to disable BG/MB*/ \ ++ {0x001f, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0}, /* 0x01f[1]=0 , disable RFC_0 control REG_RF_CTRL_8814A */ \ ++ {0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0}, /* 0x020[1]=0 , disable RFC_1 control REG_RF_CTRL_8814A */ \ ++ {0x0021, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0}, /* 0x021[1]=0 , disable RFC_2 control REG_RF_CTRL_8814A */ \ ++ {0x0076, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0}, /* 0x076[1]=0 , disable RFC_3 control REG_OPT_CTRL_8814A +2 */ \ ++ {0x0091, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xA0, 0xA0}, /* 0x91[7]=1 0x91[5]=1 , disable sps, ldo sleep mode */ \ ++ {0x0070, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3, BIT3}, /* 0x70[3]=1 enable mainbias polling */ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3, BIT3}, /*0x04[11] = 1 enable WL suspend*/ ++ ++#define RTL8814A_TRANS_CARDDIS_TO_CARDEMU \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0012, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6, BIT6},/*0x12[6] = 1 force PWM mode */ \ ++ {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, 0},/*0x15[5] = 0 turn off ZCD */ \ ++ {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6, 0},/* 0x15[6] =0 trun off ZCD output */ \ ++ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0},/*0x23[4] = 0 hpon LDO leave sleep mode */ \ ++ {0x0046, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00},/* gpio0~7 input mode */ \ ++ {0x0062, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00}, /* gpio11 input mode, gpio10~8 input mode */ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, 0}, /*0x04[10] = 0, enable SW LPS PCIE only*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3, 0}, /*0x04[11] = 0, enable WL suspend*/ \ ++ /*{0x0003, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, BIT2},*/ /*0x03[2] = 1, enable 3081*/ \ ++ {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/*PCIe DMA start*/ \ ++ {0x0071, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, 0},/*0x70[10] = 0, CPHY_MBIAS_EN disable*/ ++ ++ ++#define RTL8814A_TRANS_CARDEMU_TO_PDN \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, BIT7},/* 0x04[15] = 1*/ ++ ++#define RTL8814A_TRANS_PDN_TO_CARDEMU \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0},/* 0x04[15] = 0*/ ++ ++#define RTL8814A_TRANS_ACT_TO_LPS \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF},/*PCIe DMA stop*/ \ ++ {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x7F},/*Tx Pause*/ \ ++ {0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ ++ {0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ ++ {0x05FA, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ ++ {0x05FB, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ ++ {0x0c00, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x04}, /* 0xc00[7:0] = 4 turn off 3-wire */ \ ++ {0x0e00, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x04}, /* 0xe00[7:0] = 4 turn off 3-wire */ \ ++ {0x0002, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0},/*CCK and OFDM are disabled, and clock are gated, and RF closed*/ \ ++ {0x0002, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US},/*Delay 1us*/ \ ++ {0x0002, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0}, /* Whole BB is reset*/ \ ++ {0x1002, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0},/*CCK and OFDM are disabled, and clock are gated, and RF closed*/ \ ++ {0x0002, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US},/*Delay 1us*/ \ ++ {0x1002, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0}, /* Whole BB is reset*/ \ ++ {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x03},/*Reset MAC TRX*/ \ ++ {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0},/*check if removed later*/ \ ++ {0x05F1, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/*Respond TxOK to scheduler*/ ++ ++ ++#define RTL8814A_TRANS_LPS_TO_ACT \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, 0xFF, 0x84}, /*SDIO RPWM*/ \ ++ {0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*USB RPWM*/ \ ++ {0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*PCIe RPWM*/ \ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS}, /* Delay*/ \ ++ {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*. 0x08[4] = 0 switch TSF to 40M*/ \ ++ {0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT7, 0}, /* Polling 0x109[7]=0 TSF in 40M*/ \ ++ /*{0x0029, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6 | BIT7, 0}, */ /*. ??0x29[7:6] = 2b'00 enable BB clock*/ \ ++ {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1}, /*. 0x101[1] = 1*/ \ ++ {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF}, /*. 0x100[7:0] = 0xFF enable WMAC TRX*/ \ ++ {0x0002, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1 | BIT0, BIT1 | BIT0}, /*. 0x02[1:0] = 2b'11 enable BB macro*/ \ ++ {0x1002, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1 | BIT0, BIT1 | BIT0}, /*. 0x1002[1:0] = 2b'11 enable BB macro*/ \ ++ {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}, /*. 0x522 = 0*/ ++ ++#define RTL8814A_TRANS_END \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, 0, PWR_CMD_END, 0, 0}, ++ ++ ++extern WLAN_PWR_CFG rtl8814A_power_on_flow[RTL8814A_TRANS_CARDEMU_TO_ACT_STEPS + RTL8814A_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8814A_radio_off_flow[RTL8814A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8814A_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8814A_card_disable_flow[RTL8814A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8814A_TRANS_CARDEMU_TO_PDN_STEPS + RTL8814A_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8814A_card_enable_flow[RTL8814A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8814A_TRANS_CARDEMU_TO_PDN_STEPS + RTL8814A_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8814A_suspend_flow[RTL8814A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8814A_TRANS_CARDEMU_TO_SUS_STEPS + RTL8814A_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8814A_resume_flow[RTL8814A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8814A_TRANS_CARDEMU_TO_SUS_STEPS + RTL8814A_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8814A_hwpdn_flow[RTL8814A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8814A_TRANS_CARDEMU_TO_PDN_STEPS + RTL8814A_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8814A_enter_lps_flow[RTL8814A_TRANS_ACT_TO_LPS_STEPS + RTL8814A_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8814A_leave_lps_flow[RTL8814A_TRANS_LPS_TO_ACT_STEPS + RTL8814A_TRANS_END_STEPS]; ++ ++#endif /* __HAL8814PWRSEQ_H__ */ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/Hal8821APwrSeq.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/Hal8821APwrSeq.h +--- linux-5.11.4/3rdparty/rtl8812au/include/Hal8821APwrSeq.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/Hal8821APwrSeq.h 2021-03-07 18:16:17.084957471 +0200 +@@ -0,0 +1,200 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2016 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++#ifndef REALTEK_POWER_SEQUENCE_8821 ++#define REALTEK_POWER_SEQUENCE_8821 ++ ++#include "HalPwrSeqCmd.h" ++ ++/* ++ Check document WM-20130516-JackieLau-RTL8821A_Power_Architecture-R10.vsd ++ There are 6 HW Power States: ++ 0: POFF--Power Off ++ 1: PDN--Power Down ++ 2: CARDEMU--Card Emulation ++ 3: ACT--Active Mode ++ 4: LPS--Low Power State ++ 5: SUS--Suspend ++ ++ The transision from different states are defined below ++ TRANS_CARDEMU_TO_ACT ++ TRANS_ACT_TO_CARDEMU ++ TRANS_CARDEMU_TO_SUS ++ TRANS_SUS_TO_CARDEMU ++ TRANS_CARDEMU_TO_PDN ++ TRANS_ACT_TO_LPS ++ TRANS_LPS_TO_ACT ++ ++ TRANS_END ++*/ ++#define RTL8821A_TRANS_CARDEMU_TO_ACT_STEPS 25 ++#define RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS 15 ++#define RTL8821A_TRANS_CARDEMU_TO_SUS_STEPS 15 ++#define RTL8821A_TRANS_SUS_TO_CARDEMU_STEPS 15 ++#define RTL8821A_TRANS_CARDDIS_TO_CARDEMU_STEPS 15 ++#define RTL8821A_TRANS_CARDEMU_TO_PDN_STEPS 15 ++#define RTL8821A_TRANS_PDN_TO_CARDEMU_STEPS 15 ++#define RTL8821A_TRANS_ACT_TO_LPS_STEPS 15 ++#define RTL8821A_TRANS_LPS_TO_ACT_STEPS 15 ++#define RTL8821A_TRANS_END_STEPS 1 ++ ++ ++#define RTL8821A_TRANS_CARDEMU_TO_ACT \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0}, /*0x20[0] = 1b'1 enable LDOA12 MACRO block for all interface*/ \ ++ {0x0067, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*0x67[0] = 0 to disable BT_GPS_SEL pins*/ \ ++ {0x0001, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 1, PWRSEQ_DELAY_MS},/*Delay 1ms*/ \ ++ {0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, 0}, /*0x00[5] = 1b'0 release analog Ips to digital ,1:isolation*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, (BIT4 | BIT3 | BIT2), 0},/* disable SW LPS 0x04[10]=0 and WLSUS_EN 0x04[12:11]=0*/ \ ++ {0x0075, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0 , BIT0},/* Disable USB suspend */ \ ++ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT1, BIT1},/* wait till 0x04[17] = 1 power ready*/ \ ++ {0x0075, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0 , 0},/* Enable USB suspend */ \ ++ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/* release WLON reset 0x04[16]=1*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0},/* disable HWPDN 0x04[15]=0*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, (BIT4 | BIT3), 0},/* disable WL suspend*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/* polling until return 0*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT0, 0},/**/ \ ++ {0x004F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/*0x4C[24] = 0x4F[0] = 1, switch DPDT_SEL_P output from WL BB */\ ++ {0x0067, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, (BIT5 | BIT4), (BIT5 | BIT4)},/*0x66[13] = 0x67[5] = 1, switch for PAPE_G/PAPE_A from WL BB ; 0x66[12] = 0x67[4] = 1, switch LNAON from WL BB */\ ++ {0x0025, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6, 0},/*anapar_mac<118> , 0x25[6]=0 by wlan single function*/\ ++ {0x0049, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1},/*Enable falling edge triggering interrupt*/\ ++ {0x0063, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1},/*Enable GPIO9 interrupt mode*/\ ++ {0x0062, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0},/*Enable GPIO9 input mode*/\ ++ {0x0058, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/*Enable HSISR GPIO[C:0] interrupt*/\ ++ {0x005A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1},/*Enable HSISR GPIO9 interrupt*/\ ++ {0x007A, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x3A},/*0x7A = 0x3A start BT*/\ ++ {0x002E, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF , 0x82 },/* 0x2C[23:12]=0x820 ; XTAL trim */ \ ++ {0x0010, PWR_CUT_A_MSK , PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6 , BIT6 },/* 0x10[6]=1 ; MP·s¼W¹ï©ó0x2Cªº±±¨îÅv¡A¶·§â0x10[6]³]¬°1¤~¯àÅýWLAN±±¨î */ \ ++ ++ ++#define RTL8821A_TRANS_ACT_TO_CARDEMU \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x001F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/*0x1F[7:0] = 0 turn off RF*/ \ ++ {0x004F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0},/*0x4C[24] = 0x4F[0] = 0, switch DPDT_SEL_P output from register 0x65[2] */\ ++ {0x0049, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0},/*Enable rising edge triggering interrupt*/ \ ++ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/* release WLON reset 0x04[16]=1*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1}, /*0x04[9] = 1 turn off MAC by HW state machine*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT1, 0}, /*wait till 0x04[9] = 0 polling until return 0 to disable*/ \ ++ {0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, BIT5}, /*0x00[5] = 1b'1 analog Ips to digital ,1:isolation*/ \ ++ {0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0}, /*0x20[0] = 1b'0 disable LDOA12 MACRO block*/ \ ++ ++ ++#define RTL8821A_TRANS_CARDEMU_TO_SUS \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4 | BIT3, (BIT4 | BIT3)}, /*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3 | BIT4, BIT3}, /*0x04[12:11] = 2b'01 enable WL suspend*/ \ ++ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, BIT4}, /*0x23[4] = 1b'1 12H LDO enter sleep mode*/ \ ++ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07[7:0] = 0x20 SDIO SOP option to disable BG/MB/ACK/SWR*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3 | BIT4, BIT3 | BIT4}, /*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, BIT0}, /*Set SDIO suspend local register*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, 0}, /*wait power state to suspend*/ ++ ++#define RTL8821A_TRANS_SUS_TO_CARDEMU \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3 | BIT7, 0}, /*clear suspend enable and power down enable*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, 0}, /*Set SDIO suspend local register*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, BIT1}, /*wait power state to suspend*/\ ++ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*0x23[4] = 1b'0 12H LDO enter normal mode*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3 | BIT4, 0}, /*0x04[12:11] = 2b'01enable WL suspend*/ ++ ++#define RTL8821A_TRANS_CARDEMU_TO_CARDDIS \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07 = 0x20 , SOP option to disable BG/MB*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3 | BIT4, BIT3}, /*0x04[12:11] = 2b'01 enable WL suspend*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, BIT2}, /*0x04[10] = 1, enable SW LPS*/ \ ++ {0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 1}, /*0x48[16] = 1 to enable GPIO9 as EXT WAKEUP*/ \ ++ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, BIT4}, /*0x23[4] = 1b'1 12H LDO enter sleep mode*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, BIT0}, /*Set SDIO suspend local register*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, 0}, /*wait power state to suspend*/ ++ ++#define RTL8821A_TRANS_CARDDIS_TO_CARDEMU \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3 | BIT7, 0}, /*clear suspend enable and power down enable*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, 0}, /*Set SDIO suspend local register*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, BIT1}, /*wait power state to suspend*/\ ++ {0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0}, /*0x48[16] = 0 to disable GPIO9 as EXT WAKEUP*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3 | BIT4, 0}, /*0x04[12:11] = 2b'01enable WL suspend*/\ ++ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*0x23[4] = 1b'0 12H LDO enter normal mode*/ \ ++ {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/*PCIe DMA start*/ ++ ++ ++#define RTL8821A_TRANS_CARDEMU_TO_PDN \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, BIT4}, /*0x23[4] = 1b'1 12H LDO enter sleep mode*/ \ ++ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK | PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07[7:0] = 0x20 SOP option to disable BG/MB/ACK/SWR*/ \ ++ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0},/* 0x04[16] = 0*/\ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, BIT7},/* 0x04[15] = 1*/ ++ ++#define RTL8821A_TRANS_PDN_TO_CARDEMU \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0},/* 0x04[15] = 0*/ ++ ++#define RTL8821A_TRANS_ACT_TO_LPS \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF},/*PCIe DMA stop*/ \ ++ {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF},/*Tx Pause*/ \ ++ {0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ ++ {0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ ++ {0x05FA, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ ++ {0x05FB, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0},/*CCK and OFDM are disabled, and clock are gated*/ \ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US},/*Delay 1us*/ \ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0},/*Whole BB is reset*/ \ ++ {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x03},/*Reset MAC TRX*/ \ ++ {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0},/*check if removed later*/ \ ++ {0x0093, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00},/*When driver enter Sus/ Disable, enable LOP for BT*/ \ ++ {0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, BIT5},/*Respond TxOK to scheduler*/ \ ++ ++ ++#define RTL8821A_TRANS_LPS_TO_ACT \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, 0xFF, 0x84}, /*SDIO RPWM*/\ ++ {0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*USB RPWM*/\ ++ {0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*PCIe RPWM*/\ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS}, /*Delay*/\ ++ {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*. 0x08[4] = 0 switch TSF to 40M*/\ ++ {0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT7, 0}, /*Polling 0x109[7]=0 TSF in 40M*/\ ++ {0x0029, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6 | BIT7, 0}, /*. 0x29[7:6] = 2b'00 enable BB clock*/\ ++ {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1}, /*. 0x101[1] = 1*/\ ++ {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF}, /*. 0x100[7:0] = 0xFF enable WMAC TRX*/\ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1 | BIT0, BIT1 | BIT0}, /*. 0x02[1:0] = 2b'11 enable BB macro*/\ ++ {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}, /*. 0x522 = 0*/ ++ ++#define RTL8821A_TRANS_END \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, 0, PWR_CMD_END, 0, 0}, ++ ++ ++ extern WLAN_PWR_CFG rtl8821A_power_on_flow[RTL8821A_TRANS_CARDEMU_TO_ACT_STEPS + RTL8821A_TRANS_END_STEPS]; ++ extern WLAN_PWR_CFG rtl8821A_radio_off_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8821A_TRANS_END_STEPS]; ++ extern WLAN_PWR_CFG rtl8821A_card_disable_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8821A_TRANS_CARDEMU_TO_PDN_STEPS + RTL8821A_TRANS_END_STEPS]; ++ extern WLAN_PWR_CFG rtl8821A_card_enable_flow[RTL8821A_TRANS_CARDDIS_TO_CARDEMU_STEPS + RTL8821A_TRANS_CARDEMU_TO_ACT_STEPS + RTL8821A_TRANS_END_STEPS]; ++ extern WLAN_PWR_CFG rtl8821A_suspend_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8821A_TRANS_CARDEMU_TO_SUS_STEPS + RTL8821A_TRANS_END_STEPS]; ++ extern WLAN_PWR_CFG rtl8821A_resume_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8821A_TRANS_CARDEMU_TO_SUS_STEPS + RTL8821A_TRANS_END_STEPS]; ++ extern WLAN_PWR_CFG rtl8821A_hwpdn_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + RTL8821A_TRANS_CARDEMU_TO_PDN_STEPS + RTL8821A_TRANS_END_STEPS]; ++ extern WLAN_PWR_CFG rtl8821A_enter_lps_flow[RTL8821A_TRANS_ACT_TO_LPS_STEPS + RTL8821A_TRANS_END_STEPS]; ++ extern WLAN_PWR_CFG rtl8821A_leave_lps_flow[RTL8821A_TRANS_LPS_TO_ACT_STEPS + RTL8821A_TRANS_END_STEPS]; ++ ++#endif +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/hal_btcoex.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/hal_btcoex.h +--- linux-5.11.4/3rdparty/rtl8812au/include/hal_btcoex.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/hal_btcoex.h 2021-03-07 18:16:17.085957519 +0200 @@ -0,0 +1,97 @@ +/****************************************************************************** + * @@ -377414,11 +373637,9 @@ index 000000000..03021fee3 +u8 hal_btcoex_get_rf4ce_link_state(void); +#endif +#endif /* !__HAL_BTCOEX_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/hal_btcoex_wifionly.h linux-5.8/3rdparty/rtl8812au/include/hal_btcoex_wifionly.h -new file mode 100644 -index 000000000..c18d20e7c ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/hal_btcoex_wifionly.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/hal_btcoex_wifionly.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/hal_btcoex_wifionly.h +--- linux-5.11.4/3rdparty/rtl8812au/include/hal_btcoex_wifionly.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/hal_btcoex_wifionly.h 2021-03-07 18:16:17.085957519 +0200 @@ -0,0 +1,81 @@ +/****************************************************************************** + * @@ -377501,11 +373722,9 @@ index 000000000..c18d20e7c +#endif + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/hal_com.h linux-5.8/3rdparty/rtl8812au/include/hal_com.h -new file mode 100644 -index 000000000..a9fb90cc5 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/hal_com.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/hal_com.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/hal_com.h +--- linux-5.11.4/3rdparty/rtl8812au/include/hal_com.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/hal_com.h 2021-03-07 18:16:17.085957519 +0200 @@ -0,0 +1,719 @@ +/****************************************************************************** + * @@ -378226,11 +374445,9 @@ index 000000000..a9fb90cc5 +#endif + +#endif /* __HAL_COMMON_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/hal_com_h2c.h linux-5.8/3rdparty/rtl8812au/include/hal_com_h2c.h -new file mode 100644 -index 000000000..13158bcb6 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/hal_com_h2c.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/hal_com_h2c.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/hal_com_h2c.h +--- linux-5.11.4/3rdparty/rtl8812au/include/hal_com_h2c.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/hal_com_h2c.h 2021-03-07 18:16:17.085957519 +0200 @@ -0,0 +1,635 @@ +/****************************************************************************** + * @@ -378867,11 +375084,9 @@ index 000000000..13158bcb6 +u8 rtw_hal_set_req_per_rpt_cmd(_adapter *adapter, u8 group_macid, + u8 rpt_type, u32 macid_bitmap); +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/hal_com_led.h linux-5.8/3rdparty/rtl8812au/include/hal_com_led.h -new file mode 100644 -index 000000000..d88556df7 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/hal_com_led.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/hal_com_led.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/hal_com_led.h +--- linux-5.11.4/3rdparty/rtl8812au/include/hal_com_led.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/hal_com_led.h 2021-03-07 18:16:17.085957519 +0200 @@ -0,0 +1,437 @@ +/****************************************************************************** + * @@ -379310,11 +375525,9 @@ index 000000000..d88556df7 + +#endif /*__HAL_COMMON_LED_H_*/ + -diff --git linux-5.8/3rdparty/rtl8812au/include/hal_com_phycfg.h linux-5.8/3rdparty/rtl8812au/include/hal_com_phycfg.h -new file mode 100644 -index 000000000..3c7073dcd ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/hal_com_phycfg.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/hal_com_phycfg.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/hal_com_phycfg.h +--- linux-5.11.4/3rdparty/rtl8812au/include/hal_com_phycfg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/hal_com_phycfg.h 2021-03-07 18:16:17.085957519 +0200 @@ -0,0 +1,299 @@ +/****************************************************************************** + * @@ -379615,11 +375828,9 @@ index 000000000..3c7073dcd +#endif /* CONFIG_LOAD_PHY_PARA_FROM_FILE */ +u8 phy_check_under_survey_ch(_adapter *adapter); +#endif /* __HAL_COMMON_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/hal_com_reg.h linux-5.8/3rdparty/rtl8812au/include/hal_com_reg.h -new file mode 100644 -index 000000000..420367194 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/hal_com_reg.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/hal_com_reg.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/hal_com_reg.h +--- linux-5.11.4/3rdparty/rtl8812au/include/hal_com_reg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/hal_com_reg.h 2021-03-07 18:16:17.086957566 +0200 @@ -0,0 +1,1887 @@ +/****************************************************************************** + * @@ -381508,11 +377719,9 @@ index 000000000..420367194 +#define HAL_8188E_HW_GPIO_WPS_BIT BIT(7) + +#endif /* __HAL_COMMON_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/hal_data.h linux-5.8/3rdparty/rtl8812au/include/hal_data.h -new file mode 100644 -index 000000000..3f28e1586 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/hal_data.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/hal_data.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/hal_data.h +--- linux-5.11.4/3rdparty/rtl8812au/include/hal_data.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/hal_data.h 2021-03-07 18:16:17.086957566 +0200 @@ -0,0 +1,1105 @@ +/****************************************************************************** + * @@ -382619,11 +378828,9 @@ index 000000000..3f28e1586 +*/ + +#endif /* __HAL_DATA_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/hal_gspi.h linux-5.8/3rdparty/rtl8812au/include/hal_gspi.h -new file mode 100644 -index 000000000..51d491cdb ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/hal_gspi.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/hal_gspi.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/hal_gspi.h +--- linux-5.11.4/3rdparty/rtl8812au/include/hal_gspi.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/hal_gspi.h 2021-03-07 18:16:17.086957566 +0200 @@ -0,0 +1,26 @@ +/****************************************************************************** + * @@ -382651,11 +378858,9 @@ index 000000000..51d491cdb +u32 rtw_hal_get_gspi_tx_max_length(PADAPTER padapter, u8 queue_idx); + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/hal_ic_cfg.h linux-5.8/3rdparty/rtl8812au/include/hal_ic_cfg.h -new file mode 100644 -index 000000000..cc3ab5cad ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/hal_ic_cfg.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/hal_ic_cfg.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/hal_ic_cfg.h +--- linux-5.11.4/3rdparty/rtl8812au/include/hal_ic_cfg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/hal_ic_cfg.h 2021-03-07 18:16:17.086957566 +0200 @@ -0,0 +1,313 @@ +/****************************************************************************** + * @@ -382970,11 +379175,9 @@ index 000000000..cc3ab5cad +#endif + +#endif /*__HAL_IC_CFG_H__*/ -diff --git linux-5.8/3rdparty/rtl8812au/include/hal_intf.h linux-5.8/3rdparty/rtl8812au/include/hal_intf.h -new file mode 100644 -index 000000000..f77fa441c ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/hal_intf.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/hal_intf.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/hal_intf.h +--- linux-5.11.4/3rdparty/rtl8812au/include/hal_intf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/hal_intf.h 2021-03-07 18:16:17.086957566 +0200 @@ -0,0 +1,849 @@ +/****************************************************************************** + * @@ -383825,11 +380028,9 @@ index 000000000..f77fa441c +#endif + +#endif /* __HAL_INTF_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/hal_pg.h linux-5.8/3rdparty/rtl8812au/include/hal_pg.h -new file mode 100644 -index 000000000..b807ca84a ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/hal_pg.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/hal_pg.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/hal_pg.h +--- linux-5.11.4/3rdparty/rtl8812au/include/hal_pg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/hal_pg.h 2021-03-07 18:16:17.086957566 +0200 @@ -0,0 +1,880 @@ +/****************************************************************************** + * @@ -384711,11 +380912,9 @@ index 000000000..b807ca84a + + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/hal_phy.h linux-5.8/3rdparty/rtl8812au/include/hal_phy.h -new file mode 100644 -index 000000000..342613be1 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/hal_phy.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/hal_phy.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/hal_phy.h +--- linux-5.11.4/3rdparty/rtl8812au/include/hal_phy.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/hal_phy.h 2021-03-07 18:16:17.086957566 +0200 @@ -0,0 +1,234 @@ +/****************************************************************************** + * @@ -384951,11 +381150,9 @@ index 000000000..342613be1 + IN PADAPTER Adapter); +#endif /*#CONFIG_RF_SHADOW_RW*/ +#endif /* __HAL_COMMON_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/hal_phy_reg.h linux-5.8/3rdparty/rtl8812au/include/hal_phy_reg.h -new file mode 100644 -index 000000000..6e6a99e61 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/hal_phy_reg.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/hal_phy_reg.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/hal_phy_reg.h +--- linux-5.11.4/3rdparty/rtl8812au/include/hal_phy_reg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/hal_phy_reg.h 2021-03-07 18:16:17.086957566 +0200 @@ -0,0 +1,25 @@ +/****************************************************************************** + * @@ -384982,11 +381179,143 @@ index 000000000..6e6a99e61 +/* #endif */ + +#endif /* __HAL_PHY_REG_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/hal_sdio.h linux-5.8/3rdparty/rtl8812au/include/hal_sdio.h -new file mode 100644 -index 000000000..c3578e2fc ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/hal_sdio.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/HalPwrSeqCmd.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/HalPwrSeqCmd.h +--- linux-5.11.4/3rdparty/rtl8812au/include/HalPwrSeqCmd.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/HalPwrSeqCmd.h 2021-03-07 18:16:17.084957471 +0200 +@@ -0,0 +1,130 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++#ifndef __HALPWRSEQCMD_H__ ++#define __HALPWRSEQCMD_H__ ++ ++#include ++ ++/*---------------------------------------------*/ ++/* 3 The value of cmd: 4 bits ++ *---------------------------------------------*/ ++#define PWR_CMD_READ 0x00 ++/* offset: the read register offset ++ * msk: the mask of the read value ++ * value: N/A, left by 0 ++ * note: dirver shall implement this function by read & msk */ ++ ++#define PWR_CMD_WRITE 0x01 ++/* offset: the read register offset ++ * msk: the mask of the write bits ++ * value: write value ++ * note: driver shall implement this cmd by read & msk after write */ ++ ++#define PWR_CMD_POLLING 0x02 ++/* offset: the read register offset ++ * msk: the mask of the polled value ++ * value: the value to be polled, masked by the msd field. ++ * note: driver shall implement this cmd by ++ * do { ++ * if( (Read(offset) & msk) == (value & msk) ) ++ * break; ++ * } while(not timeout); */ ++ ++#define PWR_CMD_DELAY 0x03 ++/* offset: the value to delay ++ * msk: N/A ++ * value: the unit of delay, 0: us, 1: ms */ ++ ++#define PWR_CMD_END 0x04 ++/* offset: N/A ++ * msk: N/A ++ * value: N/A */ ++ ++/*---------------------------------------------*/ ++/* 3 The value of base: 4 bits ++ *--------------------------------------------- ++ * define the base address of each block */ ++#define PWR_BASEADDR_MAC 0x00 ++#define PWR_BASEADDR_USB 0x01 ++#define PWR_BASEADDR_PCIE 0x02 ++#define PWR_BASEADDR_SDIO 0x03 ++ ++/*---------------------------------------------*/ ++/* 3 The value of interface_msk: 4 bits ++ *---------------------------------------------*/ ++#define PWR_INTF_SDIO_MSK BIT(0) ++#define PWR_INTF_USB_MSK BIT(1) ++#define PWR_INTF_PCI_MSK BIT(2) ++#define PWR_INTF_ALL_MSK (BIT(0) | BIT(1) | BIT(2) | BIT(3)) ++ ++/*---------------------------------------------*/ ++/* 3 The value of fab_msk: 4 bits ++ *---------------------------------------------*/ ++#define PWR_FAB_TSMC_MSK BIT(0) ++#define PWR_FAB_UMC_MSK BIT(1) ++#define PWR_FAB_ALL_MSK (BIT(0) | BIT(1) | BIT(2) | BIT(3)) ++ ++/*---------------------------------------------*/ ++/* 3 The value of cut_msk: 8 bits ++ *---------------------------------------------*/ ++#define PWR_CUT_TESTCHIP_MSK BIT(0) ++#define PWR_CUT_A_MSK BIT(1) ++#define PWR_CUT_B_MSK BIT(2) ++#define PWR_CUT_C_MSK BIT(3) ++#define PWR_CUT_D_MSK BIT(4) ++#define PWR_CUT_E_MSK BIT(5) ++#define PWR_CUT_F_MSK BIT(6) ++#define PWR_CUT_G_MSK BIT(7) ++#define PWR_CUT_ALL_MSK 0xFF ++ ++ ++typedef enum _PWRSEQ_CMD_DELAY_UNIT_ { ++ PWRSEQ_DELAY_US, ++ PWRSEQ_DELAY_MS, ++} PWRSEQ_DELAY_UNIT; ++ ++typedef struct _WL_PWR_CFG_ { ++ u16 offset; ++ u8 cut_msk; ++ u8 fab_msk:4; ++ u8 interface_msk:4; ++ u8 base:4; ++ u8 cmd:4; ++ u8 msk; ++ u8 value; ++} WLAN_PWR_CFG, *PWLAN_PWR_CFG; ++ ++ ++#define GET_PWR_CFG_OFFSET(__PWR_CMD) ((__PWR_CMD).offset) ++#define GET_PWR_CFG_CUT_MASK(__PWR_CMD) ((__PWR_CMD).cut_msk) ++#define GET_PWR_CFG_FAB_MASK(__PWR_CMD) ((__PWR_CMD).fab_msk) ++#define GET_PWR_CFG_INTF_MASK(__PWR_CMD) ((__PWR_CMD).interface_msk) ++#define GET_PWR_CFG_BASE(__PWR_CMD) ((__PWR_CMD).base) ++#define GET_PWR_CFG_CMD(__PWR_CMD) ((__PWR_CMD).cmd) ++#define GET_PWR_CFG_MASK(__PWR_CMD) ((__PWR_CMD).msk) ++#define GET_PWR_CFG_VALUE(__PWR_CMD) ((__PWR_CMD).value) ++ ++ ++/* ******************************************************************************** ++ * Prototype of protected function. ++ * ******************************************************************************** */ ++u8 HalPwrSeqCmdParsing( ++ PADAPTER padapter, ++ u8 CutVersion, ++ u8 FabVersion, ++ u8 InterfaceType, ++ WLAN_PWR_CFG PwrCfgCmd[]); ++ ++#endif +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/hal_sdio.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/hal_sdio.h +--- linux-5.11.4/3rdparty/rtl8812au/include/hal_sdio.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/hal_sdio.h 2021-03-07 18:16:17.086957566 +0200 @@ -0,0 +1,56 @@ +/****************************************************************************** + * @@ -385044,11 +381373,689 @@ index 000000000..c3578e2fc +u32 cmd53_4byte_alignment(struct intf_hdl *pintfhdl, u32 addr); + +#endif /* __HAL_SDIO_H_ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/ieee80211.h linux-5.8/3rdparty/rtl8812au/include/ieee80211.h -new file mode 100644 -index 000000000..92dd31732 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/ieee80211.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/HalVerDef.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/HalVerDef.h +--- linux-5.11.4/3rdparty/rtl8812au/include/HalVerDef.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/HalVerDef.h 2021-03-07 18:16:17.084957471 +0200 +@@ -0,0 +1,201 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++#ifndef __HAL_VERSION_DEF_H__ ++#define __HAL_VERSION_DEF_H__ ++ ++#define TRUE _TRUE ++#define FALSE _FALSE ++ ++/* HAL_IC_TYPE_E */ ++typedef enum tag_HAL_IC_Type_Definition { ++ CHIP_8192S = 0, ++ CHIP_8188C = 1, ++ CHIP_8192C = 2, ++ CHIP_8192D = 3, ++ CHIP_8723A = 4, ++ CHIP_8188E = 5, ++ CHIP_8812 = 6, ++ CHIP_8821 = 7, ++ CHIP_8723B = 8, ++ CHIP_8192E = 9, ++ CHIP_8814A = 10, ++ CHIP_8703B = 11, ++ CHIP_8188F = 12, ++ CHIP_8822B = 13, ++ CHIP_8723D = 14, ++ CHIP_8821C = 15, ++ CHIP_8710B = 16, ++ CHIP_8192F = 17, ++ CHIP_8188GTV = 18, ++} HAL_IC_TYPE_E; ++ ++/* HAL_CHIP_TYPE_E */ ++typedef enum tag_HAL_CHIP_Type_Definition { ++ TEST_CHIP = 0, ++ NORMAL_CHIP = 1, ++ FPGA = 2, ++} HAL_CHIP_TYPE_E; ++ ++/* HAL_CUT_VERSION_E */ ++typedef enum tag_HAL_Cut_Version_Definition { ++ A_CUT_VERSION = 0, ++ B_CUT_VERSION = 1, ++ C_CUT_VERSION = 2, ++ D_CUT_VERSION = 3, ++ E_CUT_VERSION = 4, ++ F_CUT_VERSION = 5, ++ G_CUT_VERSION = 6, ++ H_CUT_VERSION = 7, ++ I_CUT_VERSION = 8, ++ J_CUT_VERSION = 9, ++ K_CUT_VERSION = 10, ++} HAL_CUT_VERSION_E; ++ ++/* HAL_Manufacturer */ ++typedef enum tag_HAL_Manufacturer_Version_Definition { ++ CHIP_VENDOR_TSMC = 0, ++ CHIP_VENDOR_UMC = 1, ++ CHIP_VENDOR_SMIC = 2, ++} HAL_VENDOR_E; ++ ++typedef enum tag_HAL_RF_Type_Definition { ++ RF_TYPE_1T1R = 0, ++ RF_TYPE_1T2R = 1, ++ RF_TYPE_2T2R = 2, ++ RF_TYPE_2T3R = 3, ++ RF_TYPE_2T4R = 4, ++ RF_TYPE_3T3R = 5, ++ RF_TYPE_3T4R = 6, ++ RF_TYPE_4T4R = 7, ++} HAL_RF_TYPE_E; ++ ++typedef struct tag_HAL_VERSION { ++ HAL_IC_TYPE_E ICType; ++ HAL_CHIP_TYPE_E ChipType; ++ HAL_CUT_VERSION_E CUTVersion; ++ HAL_VENDOR_E VendorType; ++ HAL_RF_TYPE_E RFType; ++ u8 ROMVer; ++} HAL_VERSION, *PHAL_VERSION; ++ ++/* VERSION_8192C VersionID; ++ * HAL_VERSION VersionID; */ ++ ++/* Get element */ ++#define GET_CVID_IC_TYPE(version) ((HAL_IC_TYPE_E)(((HAL_VERSION)version).ICType)) ++#define GET_CVID_CHIP_TYPE(version) ((HAL_CHIP_TYPE_E)(((HAL_VERSION)version).ChipType)) ++#define GET_CVID_RF_TYPE(version) ((HAL_RF_TYPE_E)(((HAL_VERSION)version).RFType)) ++#define GET_CVID_MANUFACTUER(version) ((HAL_VENDOR_E)(((HAL_VERSION)version).VendorType)) ++#define GET_CVID_CUT_VERSION(version) ((HAL_CUT_VERSION_E)(((HAL_VERSION)version).CUTVersion)) ++#define GET_CVID_ROM_VERSION(version) ((((HAL_VERSION)version).ROMVer) & ROM_VERSION_MASK) ++ ++/* ---------------------------------------------------------------------------- ++ * Common Macro. -- ++ * ---------------------------------------------------------------------------- ++ * HAL_VERSION VersionID */ ++ ++/* HAL_IC_TYPE_E */ ++#if 0 ++ #define IS_81XXC(version) (((GET_CVID_IC_TYPE(version) == CHIP_8192C) || (GET_CVID_IC_TYPE(version) == CHIP_8188C)) ? TRUE : FALSE) ++ #define IS_8723_SERIES(version) ((GET_CVID_IC_TYPE(version) == CHIP_8723A) ? TRUE : FALSE) ++ #define IS_92D(version) ((GET_CVID_IC_TYPE(version) == CHIP_8192D) ? TRUE : FALSE) ++#endif ++ ++#define IS_8188E(version) ((GET_CVID_IC_TYPE(version) == CHIP_8188E) ? TRUE : FALSE) ++#define IS_8188F(version) ((GET_CVID_IC_TYPE(version) == CHIP_8188F) ? TRUE : FALSE) ++#define IS_8188GTV(version) ((GET_CVID_IC_TYPE(version) == CHIP_8188GTV) ? TRUE : FALSE) ++#define IS_8192E(version) ((GET_CVID_IC_TYPE(version) == CHIP_8192E) ? TRUE : FALSE) ++#define IS_8812_SERIES(version) ((GET_CVID_IC_TYPE(version) == CHIP_8812) ? TRUE : FALSE) ++#define IS_8821_SERIES(version) ((GET_CVID_IC_TYPE(version) == CHIP_8821) ? TRUE : FALSE) ++#define IS_8814A_SERIES(version) ((GET_CVID_IC_TYPE(version) == CHIP_8814A) ? TRUE : FALSE) ++#define IS_8723B_SERIES(version) ((GET_CVID_IC_TYPE(version) == CHIP_8723B) ? TRUE : FALSE) ++#define IS_8703B_SERIES(version) ((GET_CVID_IC_TYPE(version) == CHIP_8703B) ? TRUE : FALSE) ++#define IS_8822B_SERIES(version) ((GET_CVID_IC_TYPE(version) == CHIP_8822B) ? TRUE : FALSE) ++#define IS_8821C_SERIES(version) ((GET_CVID_IC_TYPE(version) == CHIP_8821C) ? TRUE : FALSE) ++#define IS_8723D_SERIES(version) ((GET_CVID_IC_TYPE(version) == CHIP_8723D) ? TRUE : FALSE) ++#define IS_8710B_SERIES(version) ((GET_CVID_IC_TYPE(version) == CHIP_8710B) ? TRUE : FALSE) ++ ++#define IS_8192F_SERIES(version)\ ++ ((GET_CVID_IC_TYPE(version) == CHIP_8192F) ? TRUE : FALSE) ++/* HAL_CHIP_TYPE_E */ ++#define IS_TEST_CHIP(version) ((GET_CVID_CHIP_TYPE(version) == TEST_CHIP) ? TRUE : FALSE) ++#define IS_NORMAL_CHIP(version) ((GET_CVID_CHIP_TYPE(version) == NORMAL_CHIP) ? TRUE : FALSE) ++ ++/* HAL_CUT_VERSION_E */ ++#define IS_A_CUT(version) ((GET_CVID_CUT_VERSION(version) == A_CUT_VERSION) ? TRUE : FALSE) ++#define IS_B_CUT(version) ((GET_CVID_CUT_VERSION(version) == B_CUT_VERSION) ? TRUE : FALSE) ++#define IS_C_CUT(version) ((GET_CVID_CUT_VERSION(version) == C_CUT_VERSION) ? TRUE : FALSE) ++#define IS_D_CUT(version) ((GET_CVID_CUT_VERSION(version) == D_CUT_VERSION) ? TRUE : FALSE) ++#define IS_E_CUT(version) ((GET_CVID_CUT_VERSION(version) == E_CUT_VERSION) ? TRUE : FALSE) ++#define IS_F_CUT(version) ((GET_CVID_CUT_VERSION(version) == F_CUT_VERSION) ? TRUE : FALSE) ++#define IS_I_CUT(version) ((GET_CVID_CUT_VERSION(version) == I_CUT_VERSION) ? TRUE : FALSE) ++#define IS_J_CUT(version) ((GET_CVID_CUT_VERSION(version) == J_CUT_VERSION) ? TRUE : FALSE) ++#define IS_K_CUT(version) ((GET_CVID_CUT_VERSION(version) == K_CUT_VERSION) ? TRUE : FALSE) ++ ++/* HAL_VENDOR_E */ ++#define IS_CHIP_VENDOR_TSMC(version) ((GET_CVID_MANUFACTUER(version) == CHIP_VENDOR_TSMC) ? TRUE : FALSE) ++#define IS_CHIP_VENDOR_UMC(version) ((GET_CVID_MANUFACTUER(version) == CHIP_VENDOR_UMC) ? TRUE : FALSE) ++#define IS_CHIP_VENDOR_SMIC(version) ((GET_CVID_MANUFACTUER(version) == CHIP_VENDOR_SMIC) ? TRUE : FALSE) ++ ++/* HAL_RF_TYPE_E */ ++#define IS_1T1R(version) ((GET_CVID_RF_TYPE(version) == RF_TYPE_1T1R) ? TRUE : FALSE) ++#define IS_1T2R(version) ((GET_CVID_RF_TYPE(version) == RF_TYPE_1T2R) ? TRUE : FALSE) ++#define IS_2T2R(version) ((GET_CVID_RF_TYPE(version) == RF_TYPE_2T2R) ? TRUE : FALSE) ++#define IS_3T3R(version) ((GET_CVID_RF_TYPE(version) == RF_TYPE_3T3R) ? TRUE : FALSE) ++#define IS_3T4R(version) ((GET_CVID_RF_TYPE(version) == RF_TYPE_3T4R) ? TRUE : FALSE) ++#define IS_4T4R(version) ((GET_CVID_RF_TYPE(version) == RF_TYPE_4T4R) ? TRUE : FALSE) ++ ++ ++ ++/* ---------------------------------------------------------------------------- ++ * Chip version Macro. -- ++ * ---------------------------------------------------------------------------- */ ++#if 0 ++ #define IS_81XXC_TEST_CHIP(version) ((IS_81XXC(version) && (!IS_NORMAL_CHIP(version))) ? TRUE : FALSE) ++ ++ #define IS_92C_SERIAL(version) ((IS_81XXC(version) && IS_2T2R(version)) ? TRUE : FALSE) ++ #define IS_81xxC_VENDOR_UMC_A_CUT(version) (IS_81XXC(version) ? (IS_CHIP_VENDOR_UMC(version) ? (IS_A_CUT(version) ? TRUE : FALSE) : FALSE) : FALSE) ++ #define IS_81xxC_VENDOR_UMC_B_CUT(version) (IS_81XXC(version) ? (IS_CHIP_VENDOR_UMC(version) ? (IS_B_CUT(version) ? TRUE : FALSE) : FALSE) : FALSE) ++ #define IS_81xxC_VENDOR_UMC_C_CUT(version) (IS_81XXC(version) ? (IS_CHIP_VENDOR_UMC(version) ? (IS_C_CUT(version) ? TRUE : FALSE) : FALSE) : FALSE) ++ ++ #define IS_NORMAL_CHIP92D(version) ((IS_92D(version)) ? ((GET_CVID_CHIP_TYPE(version) == NORMAL_CHIP) ? TRUE : FALSE) : FALSE) ++ ++ #define IS_92D_SINGLEPHY(version) ((IS_92D(version)) ? (IS_2T2R(version) ? TRUE : FALSE) : FALSE) ++ #define IS_92D_C_CUT(version) ((IS_92D(version)) ? (IS_C_CUT(version) ? TRUE : FALSE) : FALSE) ++ #define IS_92D_D_CUT(version) ((IS_92D(version)) ? (IS_D_CUT(version) ? TRUE : FALSE) : FALSE) ++ #define IS_92D_E_CUT(version) ((IS_92D(version)) ? (IS_E_CUT(version) ? TRUE : FALSE) : FALSE) ++ ++ #define IS_8723A_A_CUT(version) ((IS_8723_SERIES(version)) ? (IS_A_CUT(version) ? TRUE : FALSE) : FALSE) ++ #define IS_8723A_B_CUT(version) ((IS_8723_SERIES(version)) ? (IS_B_CUT(version) ? TRUE : FALSE) : FALSE) ++#endif ++#define IS_VENDOR_8188E_I_CUT_SERIES(_Adapter) ((IS_8188E(GET_HAL_DATA(_Adapter)->version_id)) ? ((GET_CVID_CUT_VERSION(GET_HAL_DATA(_Adapter)->version_id) >= I_CUT_VERSION) ? TRUE : FALSE) : FALSE) ++#define IS_VENDOR_8812A_TEST_CHIP(_Adapter) ((IS_8812_SERIES(GET_HAL_DATA(_Adapter)->version_id)) ? ((IS_NORMAL_CHIP(GET_HAL_DATA(_Adapter)->version_id)) ? FALSE : TRUE) : FALSE) ++#define IS_VENDOR_8812A_MP_CHIP(_Adapter) ((IS_8812_SERIES(GET_HAL_DATA(_Adapter)->version_id)) ? ((IS_NORMAL_CHIP(GET_HAL_DATA(_Adapter)->version_id)) ? TRUE : FALSE) : FALSE) ++#define IS_VENDOR_8812A_C_CUT(_Adapter) ((IS_8812_SERIES(GET_HAL_DATA(_Adapter)->version_id)) ? ((GET_CVID_CUT_VERSION(GET_HAL_DATA(_Adapter)->version_id) == C_CUT_VERSION) ? TRUE : FALSE) : FALSE) ++ ++#define IS_VENDOR_8821A_TEST_CHIP(_Adapter) ((IS_8821_SERIES(GET_HAL_DATA(_Adapter)->version_id)) ? ((IS_NORMAL_CHIP(GET_HAL_DATA(_Adapter)->version_id)) ? FALSE : TRUE) : FALSE) ++#define IS_VENDOR_8821A_MP_CHIP(_Adapter) ((IS_8821_SERIES(GET_HAL_DATA(_Adapter)->version_id)) ? ((IS_NORMAL_CHIP(GET_HAL_DATA(_Adapter)->version_id)) ? TRUE : FALSE) : FALSE) ++ ++#define IS_VENDOR_8192E_B_CUT(_Adapter) ((GET_CVID_CUT_VERSION(GET_HAL_DATA(_Adapter)->version_id) == B_CUT_VERSION) ? TRUE : FALSE) ++ ++#define IS_VENDOR_8723B_TEST_CHIP(_Adapter) ((IS_8723B_SERIES(GET_HAL_DATA(_Adapter)->version_id)) ? ((IS_NORMAL_CHIP(GET_HAL_DATA(_Adapter)->version_id)) ? FALSE : TRUE) : FALSE) ++#define IS_VENDOR_8723B_MP_CHIP(_Adapter) ((IS_8723B_SERIES(GET_HAL_DATA(_Adapter)->version_id)) ? ((IS_NORMAL_CHIP(GET_HAL_DATA(_Adapter)->version_id)) ? TRUE : FALSE) : FALSE) ++ ++#define IS_VENDOR_8703B_TEST_CHIP(_Adapter) ((IS_8703B_SERIES(GET_HAL_DATA(_Adapter)->version_id)) ? ((IS_NORMAL_CHIP(GET_HAL_DATA(_Adapter)->version_id)) ? FALSE : TRUE) : FALSE) ++#define IS_VENDOR_8703B_MP_CHIP(_Adapter) ((IS_8703B_SERIES(GET_HAL_DATA(_Adapter)->version_id)) ? ((IS_NORMAL_CHIP(GET_HAL_DATA(_Adapter)->version_id)) ? TRUE : FALSE) : FALSE) ++#define IS_VENDOR_8814A_TEST_CHIP(_Adapter) ((IS_8814A_SERIES(GET_HAL_DATA(_Adapter)->version_id)) ? ((IS_NORMAL_CHIP(GET_HAL_DATA(_Adapter)->version_id)) ? FALSE : TRUE) : FALSE) ++#define IS_VENDOR_8814A_MP_CHIP(_Adapter) ((IS_8814A_SERIES(GET_HAL_DATA(_Adapter)->version_id)) ? ((IS_NORMAL_CHIP(GET_HAL_DATA(_Adapter)->version_id)) ? TRUE : FALSE) : FALSE) ++ ++#endif +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/ieee80211_ext.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/ieee80211_ext.h +--- linux-5.11.4/3rdparty/rtl8812au/include/ieee80211_ext.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/ieee80211_ext.h 2021-03-07 18:16:17.087957613 +0200 +@@ -0,0 +1,471 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++#ifndef __IEEE80211_EXT_H ++#define __IEEE80211_EXT_H ++ ++#include ++#include ++#include ++ ++#define WMM_OUI_TYPE 2 ++#define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0 ++#define WMM_OUI_SUBTYPE_PARAMETER_ELEMENT 1 ++#define WMM_OUI_SUBTYPE_TSPEC_ELEMENT 2 ++#define WMM_VERSION 1 ++ ++#define WPA_PROTO_WPA BIT(0) ++#define WPA_PROTO_RSN BIT(1) ++ ++#define WPA_KEY_MGMT_IEEE8021X BIT(0) ++#define WPA_KEY_MGMT_PSK BIT(1) ++#define WPA_KEY_MGMT_NONE BIT(2) ++#define WPA_KEY_MGMT_IEEE8021X_NO_WPA BIT(3) ++#define WPA_KEY_MGMT_WPA_NONE BIT(4) ++ ++ ++#define WPA_CAPABILITY_PREAUTH BIT(0) ++#define WPA_CAPABILITY_MGMT_FRAME_PROTECTION BIT(6) ++#define WPA_CAPABILITY_PEERKEY_ENABLED BIT(9) ++ ++ ++#define PMKID_LEN 16 ++ ++ ++#ifdef PLATFORM_LINUX ++struct wpa_ie_hdr { ++ u8 elem_id; ++ u8 len; ++ u8 oui[4]; /* 24-bit OUI followed by 8-bit OUI type */ ++ u8 version[2]; /* little endian */ ++} __attribute__((packed)); ++ ++struct rsn_ie_hdr { ++ u8 elem_id; /* WLAN_EID_RSN */ ++ u8 len; ++ u8 version[2]; /* little endian */ ++} __attribute__((packed)); ++ ++struct wme_ac_parameter { ++#if defined(CONFIG_LITTLE_ENDIAN) ++ /* byte 1 */ ++ u8 aifsn:4, ++ acm:1, ++ aci:2, ++ reserved:1; ++ ++ /* byte 2 */ ++ u8 eCWmin:4, ++ eCWmax:4; ++#elif defined(CONFIG_BIG_ENDIAN) ++ /* byte 1 */ ++ u8 reserved:1, ++ aci:2, ++ acm:1, ++ aifsn:4; ++ ++ /* byte 2 */ ++ u8 eCWmax:4, ++ eCWmin:4; ++#else ++#error "Please fix " ++#endif ++ ++ /* bytes 3 & 4 */ ++ u16 txopLimit; ++} __attribute__((packed)); ++ ++struct wme_parameter_element { ++ /* required fields for WME version 1 */ ++ u8 oui[3]; ++ u8 oui_type; ++ u8 oui_subtype; ++ u8 version; ++ u8 acInfo; ++ u8 reserved; ++ struct wme_ac_parameter ac[4]; ++ ++} __attribute__((packed)); ++ ++#endif ++ ++#ifdef PLATFORM_WINDOWS ++ ++#pragma pack(1) ++ ++struct wpa_ie_hdr { ++ u8 elem_id; ++ u8 len; ++ u8 oui[4]; /* 24-bit OUI followed by 8-bit OUI type */ ++ u8 version[2]; /* little endian */ ++}; ++ ++struct rsn_ie_hdr { ++ u8 elem_id; /* WLAN_EID_RSN */ ++ u8 len; ++ u8 version[2]; /* little endian */ ++}; ++ ++#pragma pack() ++ ++#endif ++ ++#define WPA_PUT_LE16(a, val) \ ++ do { \ ++ (a)[1] = ((u16) (val)) >> 8; \ ++ (a)[0] = ((u16) (val)) & 0xff; \ ++ } while (0) ++ ++#define WPA_PUT_BE32(a, val) \ ++ do { \ ++ (a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff); \ ++ (a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff); \ ++ (a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff); \ ++ (a)[3] = (u8) (((u32) (val)) & 0xff); \ ++ } while (0) ++ ++#define WPA_PUT_LE32(a, val) \ ++ do { \ ++ (a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff); \ ++ (a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff); \ ++ (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ ++ (a)[0] = (u8) (((u32) (val)) & 0xff); \ ++ } while (0) ++ ++#define RSN_SELECTOR_PUT(a, val) WPA_PUT_BE32((u8 *) (a), (val)) ++/* #define RSN_SELECTOR_PUT(a, val) WPA_PUT_LE32((u8 *) (a), (val)) */ ++ ++ ++ ++/* Action category code */ ++enum ieee80211_category { ++ WLAN_CATEGORY_SPECTRUM_MGMT = 0, ++ WLAN_CATEGORY_QOS = 1, ++ WLAN_CATEGORY_DLS = 2, ++ WLAN_CATEGORY_BACK = 3, ++ WLAN_CATEGORY_HT = 7, ++ WLAN_CATEGORY_WMM = 17, ++}; ++ ++/* SPECTRUM_MGMT action code */ ++enum ieee80211_spectrum_mgmt_actioncode { ++ WLAN_ACTION_SPCT_MSR_REQ = 0, ++ WLAN_ACTION_SPCT_MSR_RPRT = 1, ++ WLAN_ACTION_SPCT_TPC_REQ = 2, ++ WLAN_ACTION_SPCT_TPC_RPRT = 3, ++ WLAN_ACTION_SPCT_CHL_SWITCH = 4, ++ WLAN_ACTION_SPCT_EXT_CHL_SWITCH = 5, ++}; ++ ++/* BACK action code */ ++enum ieee80211_back_actioncode { ++ WLAN_ACTION_ADDBA_REQ = 0, ++ WLAN_ACTION_ADDBA_RESP = 1, ++ WLAN_ACTION_DELBA = 2, ++}; ++ ++/* HT features action code */ ++enum ieee80211_ht_actioncode { ++ WLAN_ACTION_NOTIFY_CH_WIDTH = 0, ++ WLAN_ACTION_SM_PS = 1, ++ WLAN_ACTION_PSPM = 2, ++ WLAN_ACTION_PCO_PHASE = 3, ++ WLAN_ACTION_MIMO_CSI_MX = 4, ++ WLAN_ACTION_MIMO_NONCP_BF = 5, ++ WLAN_ACTION_MIMP_CP_BF = 6, ++ WLAN_ACTION_ASEL_INDICATES_FB = 7, ++ WLAN_ACTION_HI_INFO_EXCHG = 8, ++}; ++ ++/* BACK (block-ack) parties */ ++enum ieee80211_back_parties { ++ WLAN_BACK_RECIPIENT = 0, ++ WLAN_BACK_INITIATOR = 1, ++ WLAN_BACK_TIMER = 2, ++}; ++ ++#ifdef PLATFORM_LINUX ++ ++struct ieee80211_mgmt { ++ u16 frame_control; ++ u16 duration; ++ u8 da[6]; ++ u8 sa[6]; ++ u8 bssid[6]; ++ u16 seq_ctrl; ++ union { ++ struct { ++ u16 auth_alg; ++ u16 auth_transaction; ++ u16 status_code; ++ /* possibly followed by Challenge text */ ++ u8 variable[0]; ++ } __attribute__((packed)) auth; ++ struct { ++ u16 reason_code; ++ } __attribute__((packed)) deauth; ++ struct { ++ u16 capab_info; ++ u16 listen_interval; ++ /* followed by SSID and Supported rates */ ++ u8 variable[0]; ++ } __attribute__((packed)) assoc_req; ++ struct { ++ u16 capab_info; ++ u16 status_code; ++ u16 aid; ++ /* followed by Supported rates */ ++ u8 variable[0]; ++ } __attribute__((packed)) assoc_resp, reassoc_resp; ++ struct { ++ u16 capab_info; ++ u16 listen_interval; ++ u8 current_ap[6]; ++ /* followed by SSID and Supported rates */ ++ u8 variable[0]; ++ } __attribute__((packed)) reassoc_req; ++ struct { ++ u16 reason_code; ++ } __attribute__((packed)) disassoc; ++ struct { ++ __le64 timestamp; ++ u16 beacon_int; ++ u16 capab_info; ++ /* followed by some of SSID, Supported rates, ++ * FH Params, DS Params, CF Params, IBSS Params, TIM */ ++ u8 variable[0]; ++ } __attribute__((packed)) beacon; ++ struct { ++ /* only variable items: SSID, Supported rates */ ++ u8 variable[0]; ++ } __attribute__((packed)) probe_req; ++ struct { ++ __le64 timestamp; ++ u16 beacon_int; ++ u16 capab_info; ++ /* followed by some of SSID, Supported rates, ++ * FH Params, DS Params, CF Params, IBSS Params */ ++ u8 variable[0]; ++ } __attribute__((packed)) probe_resp; ++ struct { ++ u8 category; ++ union { ++ struct { ++ u8 action_code; ++ u8 dialog_token; ++ u8 status_code; ++ u8 variable[0]; ++ } __attribute__((packed)) wme_action; ++#if 0 ++ struct { ++ u8 action_code; ++ u8 element_id; ++ u8 length; ++ struct ieee80211_channel_sw_ie sw_elem; ++ } __attribute__((packed)) chan_switch; ++ struct { ++ u8 action_code; ++ u8 dialog_token; ++ u8 element_id; ++ u8 length; ++ struct ieee80211_msrment_ie msr_elem; ++ } __attribute__((packed)) measurement; ++#endif ++ struct { ++ u8 action_code; ++ u8 dialog_token; ++ u16 capab; ++ u16 timeout; ++ u16 start_seq_num; ++ } __attribute__((packed)) addba_req; ++ struct { ++ u8 action_code; ++ u8 dialog_token; ++ u16 status; ++ u16 capab; ++ u16 timeout; ++ } __attribute__((packed)) addba_resp; ++ struct { ++ u8 action_code; ++ u16 params; ++ u16 reason_code; ++ } __attribute__((packed)) delba; ++ struct { ++ u8 action_code; ++ /* capab_info for open and confirm, ++ * reason for close ++ */ ++ u16 aux; ++ /* Followed in plink_confirm by status ++ * code, AID and supported rates, ++ * and directly by supported rates in ++ * plink_open and plink_close ++ */ ++ u8 variable[0]; ++ } __attribute__((packed)) plink_action; ++ struct { ++ u8 action_code; ++ u8 variable[0]; ++ } __attribute__((packed)) mesh_action; ++ } __attribute__((packed)) u; ++ } __attribute__((packed)) action; ++ } __attribute__((packed)) u; ++} __attribute__((packed)); ++ ++#endif ++ ++ ++#ifdef PLATFORM_WINDOWS ++ ++#pragma pack(1) ++ ++struct ieee80211_mgmt { ++ u16 frame_control; ++ u16 duration; ++ u8 da[6]; ++ u8 sa[6]; ++ u8 bssid[6]; ++ u16 seq_ctrl; ++ union { ++ struct { ++ u16 auth_alg; ++ u16 auth_transaction; ++ u16 status_code; ++ /* possibly followed by Challenge text */ ++ u8 variable[0]; ++ } auth; ++ struct { ++ u16 reason_code; ++ } deauth; ++ struct { ++ u16 capab_info; ++ u16 listen_interval; ++ /* followed by SSID and Supported rates */ ++ u8 variable[0]; ++ } assoc_req; ++ struct { ++ u16 capab_info; ++ u16 status_code; ++ u16 aid; ++ /* followed by Supported rates */ ++ u8 variable[0]; ++ } assoc_resp, reassoc_resp; ++ struct { ++ u16 capab_info; ++ u16 listen_interval; ++ u8 current_ap[6]; ++ /* followed by SSID and Supported rates */ ++ u8 variable[0]; ++ } reassoc_req; ++ struct { ++ u16 reason_code; ++ } disassoc; ++#if 0 ++ struct { ++ __le64 timestamp; ++ u16 beacon_int; ++ u16 capab_info; ++ /* followed by some of SSID, Supported rates, ++ * FH Params, DS Params, CF Params, IBSS Params, TIM */ ++ u8 variable[0]; ++ } beacon; ++ struct { ++ /* only variable items: SSID, Supported rates */ ++ u8 variable[0]; ++ } probe_req; ++ ++ struct { ++ __le64 timestamp; ++ u16 beacon_int; ++ u16 capab_info; ++ /* followed by some of SSID, Supported rates, ++ * FH Params, DS Params, CF Params, IBSS Params */ ++ u8 variable[0]; ++ } probe_resp; ++#endif ++ struct { ++ u8 category; ++ union { ++ struct { ++ u8 action_code; ++ u8 dialog_token; ++ u8 status_code; ++ u8 variable[0]; ++ } wme_action; ++ #if 0 ++ struct{ ++ u8 action_code; ++ u8 element_id; ++ u8 length; ++ struct ieee80211_channel_sw_ie sw_elem; ++ } chan_switch; ++ struct{ ++ u8 action_code; ++ u8 dialog_token; ++ u8 element_id; ++ u8 length; ++ struct ieee80211_msrment_ie msr_elem; ++ } measurement; ++ #endif ++ struct { ++ u8 action_code; ++ u8 dialog_token; ++ u16 capab; ++ u16 timeout; ++ u16 start_seq_num; ++ } addba_req; ++ struct { ++ u8 action_code; ++ u8 dialog_token; ++ u16 status; ++ u16 capab; ++ u16 timeout; ++ } addba_resp; ++ struct { ++ u8 action_code; ++ u16 params; ++ u16 reason_code; ++ } delba; ++ struct { ++ u8 action_code; ++ /* capab_info for open and confirm, ++ * reason for close ++ */ ++ u16 aux; ++ /* Followed in plink_confirm by status ++ * code, AID and supported rates, ++ * and directly by supported rates in ++ * plink_open and plink_close ++ */ ++ u8 variable[0]; ++ } plink_action; ++ struct { ++ u8 action_code; ++ u8 variable[0]; ++ } mesh_action; ++ } u; ++ } action; ++ } u; ++} ; ++ ++#pragma pack() ++ ++#endif ++ ++/* mgmt header + 1 byte category code */ ++#define IEEE80211_MIN_ACTION_SIZE FIELD_OFFSET(struct ieee80211_mgmt, u.action.u) ++ ++ ++ ++#endif +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/ieee80211.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/ieee80211.h +--- linux-5.11.4/3rdparty/rtl8812au/include/ieee80211.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/ieee80211.h 2021-03-07 18:16:17.087957613 +0200 @@ -0,0 +1,2204 @@ +/****************************************************************************** + * @@ -387254,488 +384261,9 @@ index 000000000..92dd31732 + + +#endif /* IEEE80211_H */ -diff --git linux-5.8/3rdparty/rtl8812au/include/ieee80211_ext.h linux-5.8/3rdparty/rtl8812au/include/ieee80211_ext.h -new file mode 100644 -index 000000000..94a8e582d ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/ieee80211_ext.h -@@ -0,0 +1,471 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+#ifndef __IEEE80211_EXT_H -+#define __IEEE80211_EXT_H -+ -+#include -+#include -+#include -+ -+#define WMM_OUI_TYPE 2 -+#define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0 -+#define WMM_OUI_SUBTYPE_PARAMETER_ELEMENT 1 -+#define WMM_OUI_SUBTYPE_TSPEC_ELEMENT 2 -+#define WMM_VERSION 1 -+ -+#define WPA_PROTO_WPA BIT(0) -+#define WPA_PROTO_RSN BIT(1) -+ -+#define WPA_KEY_MGMT_IEEE8021X BIT(0) -+#define WPA_KEY_MGMT_PSK BIT(1) -+#define WPA_KEY_MGMT_NONE BIT(2) -+#define WPA_KEY_MGMT_IEEE8021X_NO_WPA BIT(3) -+#define WPA_KEY_MGMT_WPA_NONE BIT(4) -+ -+ -+#define WPA_CAPABILITY_PREAUTH BIT(0) -+#define WPA_CAPABILITY_MGMT_FRAME_PROTECTION BIT(6) -+#define WPA_CAPABILITY_PEERKEY_ENABLED BIT(9) -+ -+ -+#define PMKID_LEN 16 -+ -+ -+#ifdef PLATFORM_LINUX -+struct wpa_ie_hdr { -+ u8 elem_id; -+ u8 len; -+ u8 oui[4]; /* 24-bit OUI followed by 8-bit OUI type */ -+ u8 version[2]; /* little endian */ -+} __attribute__((packed)); -+ -+struct rsn_ie_hdr { -+ u8 elem_id; /* WLAN_EID_RSN */ -+ u8 len; -+ u8 version[2]; /* little endian */ -+} __attribute__((packed)); -+ -+struct wme_ac_parameter { -+#if defined(CONFIG_LITTLE_ENDIAN) -+ /* byte 1 */ -+ u8 aifsn:4, -+ acm:1, -+ aci:2, -+ reserved:1; -+ -+ /* byte 2 */ -+ u8 eCWmin:4, -+ eCWmax:4; -+#elif defined(CONFIG_BIG_ENDIAN) -+ /* byte 1 */ -+ u8 reserved:1, -+ aci:2, -+ acm:1, -+ aifsn:4; -+ -+ /* byte 2 */ -+ u8 eCWmax:4, -+ eCWmin:4; -+#else -+#error "Please fix " -+#endif -+ -+ /* bytes 3 & 4 */ -+ u16 txopLimit; -+} __attribute__((packed)); -+ -+struct wme_parameter_element { -+ /* required fields for WME version 1 */ -+ u8 oui[3]; -+ u8 oui_type; -+ u8 oui_subtype; -+ u8 version; -+ u8 acInfo; -+ u8 reserved; -+ struct wme_ac_parameter ac[4]; -+ -+} __attribute__((packed)); -+ -+#endif -+ -+#ifdef PLATFORM_WINDOWS -+ -+#pragma pack(1) -+ -+struct wpa_ie_hdr { -+ u8 elem_id; -+ u8 len; -+ u8 oui[4]; /* 24-bit OUI followed by 8-bit OUI type */ -+ u8 version[2]; /* little endian */ -+}; -+ -+struct rsn_ie_hdr { -+ u8 elem_id; /* WLAN_EID_RSN */ -+ u8 len; -+ u8 version[2]; /* little endian */ -+}; -+ -+#pragma pack() -+ -+#endif -+ -+#define WPA_PUT_LE16(a, val) \ -+ do { \ -+ (a)[1] = ((u16) (val)) >> 8; \ -+ (a)[0] = ((u16) (val)) & 0xff; \ -+ } while (0) -+ -+#define WPA_PUT_BE32(a, val) \ -+ do { \ -+ (a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff); \ -+ (a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff); \ -+ (a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff); \ -+ (a)[3] = (u8) (((u32) (val)) & 0xff); \ -+ } while (0) -+ -+#define WPA_PUT_LE32(a, val) \ -+ do { \ -+ (a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff); \ -+ (a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff); \ -+ (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ -+ (a)[0] = (u8) (((u32) (val)) & 0xff); \ -+ } while (0) -+ -+#define RSN_SELECTOR_PUT(a, val) WPA_PUT_BE32((u8 *) (a), (val)) -+/* #define RSN_SELECTOR_PUT(a, val) WPA_PUT_LE32((u8 *) (a), (val)) */ -+ -+ -+ -+/* Action category code */ -+enum ieee80211_category { -+ WLAN_CATEGORY_SPECTRUM_MGMT = 0, -+ WLAN_CATEGORY_QOS = 1, -+ WLAN_CATEGORY_DLS = 2, -+ WLAN_CATEGORY_BACK = 3, -+ WLAN_CATEGORY_HT = 7, -+ WLAN_CATEGORY_WMM = 17, -+}; -+ -+/* SPECTRUM_MGMT action code */ -+enum ieee80211_spectrum_mgmt_actioncode { -+ WLAN_ACTION_SPCT_MSR_REQ = 0, -+ WLAN_ACTION_SPCT_MSR_RPRT = 1, -+ WLAN_ACTION_SPCT_TPC_REQ = 2, -+ WLAN_ACTION_SPCT_TPC_RPRT = 3, -+ WLAN_ACTION_SPCT_CHL_SWITCH = 4, -+ WLAN_ACTION_SPCT_EXT_CHL_SWITCH = 5, -+}; -+ -+/* BACK action code */ -+enum ieee80211_back_actioncode { -+ WLAN_ACTION_ADDBA_REQ = 0, -+ WLAN_ACTION_ADDBA_RESP = 1, -+ WLAN_ACTION_DELBA = 2, -+}; -+ -+/* HT features action code */ -+enum ieee80211_ht_actioncode { -+ WLAN_ACTION_NOTIFY_CH_WIDTH = 0, -+ WLAN_ACTION_SM_PS = 1, -+ WLAN_ACTION_PSPM = 2, -+ WLAN_ACTION_PCO_PHASE = 3, -+ WLAN_ACTION_MIMO_CSI_MX = 4, -+ WLAN_ACTION_MIMO_NONCP_BF = 5, -+ WLAN_ACTION_MIMP_CP_BF = 6, -+ WLAN_ACTION_ASEL_INDICATES_FB = 7, -+ WLAN_ACTION_HI_INFO_EXCHG = 8, -+}; -+ -+/* BACK (block-ack) parties */ -+enum ieee80211_back_parties { -+ WLAN_BACK_RECIPIENT = 0, -+ WLAN_BACK_INITIATOR = 1, -+ WLAN_BACK_TIMER = 2, -+}; -+ -+#ifdef PLATFORM_LINUX -+ -+struct ieee80211_mgmt { -+ u16 frame_control; -+ u16 duration; -+ u8 da[6]; -+ u8 sa[6]; -+ u8 bssid[6]; -+ u16 seq_ctrl; -+ union { -+ struct { -+ u16 auth_alg; -+ u16 auth_transaction; -+ u16 status_code; -+ /* possibly followed by Challenge text */ -+ u8 variable[0]; -+ } __attribute__((packed)) auth; -+ struct { -+ u16 reason_code; -+ } __attribute__((packed)) deauth; -+ struct { -+ u16 capab_info; -+ u16 listen_interval; -+ /* followed by SSID and Supported rates */ -+ u8 variable[0]; -+ } __attribute__((packed)) assoc_req; -+ struct { -+ u16 capab_info; -+ u16 status_code; -+ u16 aid; -+ /* followed by Supported rates */ -+ u8 variable[0]; -+ } __attribute__((packed)) assoc_resp, reassoc_resp; -+ struct { -+ u16 capab_info; -+ u16 listen_interval; -+ u8 current_ap[6]; -+ /* followed by SSID and Supported rates */ -+ u8 variable[0]; -+ } __attribute__((packed)) reassoc_req; -+ struct { -+ u16 reason_code; -+ } __attribute__((packed)) disassoc; -+ struct { -+ __le64 timestamp; -+ u16 beacon_int; -+ u16 capab_info; -+ /* followed by some of SSID, Supported rates, -+ * FH Params, DS Params, CF Params, IBSS Params, TIM */ -+ u8 variable[0]; -+ } __attribute__((packed)) beacon; -+ struct { -+ /* only variable items: SSID, Supported rates */ -+ u8 variable[0]; -+ } __attribute__((packed)) probe_req; -+ struct { -+ __le64 timestamp; -+ u16 beacon_int; -+ u16 capab_info; -+ /* followed by some of SSID, Supported rates, -+ * FH Params, DS Params, CF Params, IBSS Params */ -+ u8 variable[0]; -+ } __attribute__((packed)) probe_resp; -+ struct { -+ u8 category; -+ union { -+ struct { -+ u8 action_code; -+ u8 dialog_token; -+ u8 status_code; -+ u8 variable[0]; -+ } __attribute__((packed)) wme_action; -+#if 0 -+ struct { -+ u8 action_code; -+ u8 element_id; -+ u8 length; -+ struct ieee80211_channel_sw_ie sw_elem; -+ } __attribute__((packed)) chan_switch; -+ struct { -+ u8 action_code; -+ u8 dialog_token; -+ u8 element_id; -+ u8 length; -+ struct ieee80211_msrment_ie msr_elem; -+ } __attribute__((packed)) measurement; -+#endif -+ struct { -+ u8 action_code; -+ u8 dialog_token; -+ u16 capab; -+ u16 timeout; -+ u16 start_seq_num; -+ } __attribute__((packed)) addba_req; -+ struct { -+ u8 action_code; -+ u8 dialog_token; -+ u16 status; -+ u16 capab; -+ u16 timeout; -+ } __attribute__((packed)) addba_resp; -+ struct { -+ u8 action_code; -+ u16 params; -+ u16 reason_code; -+ } __attribute__((packed)) delba; -+ struct { -+ u8 action_code; -+ /* capab_info for open and confirm, -+ * reason for close -+ */ -+ u16 aux; -+ /* Followed in plink_confirm by status -+ * code, AID and supported rates, -+ * and directly by supported rates in -+ * plink_open and plink_close -+ */ -+ u8 variable[0]; -+ } __attribute__((packed)) plink_action; -+ struct { -+ u8 action_code; -+ u8 variable[0]; -+ } __attribute__((packed)) mesh_action; -+ } __attribute__((packed)) u; -+ } __attribute__((packed)) action; -+ } __attribute__((packed)) u; -+} __attribute__((packed)); -+ -+#endif -+ -+ -+#ifdef PLATFORM_WINDOWS -+ -+#pragma pack(1) -+ -+struct ieee80211_mgmt { -+ u16 frame_control; -+ u16 duration; -+ u8 da[6]; -+ u8 sa[6]; -+ u8 bssid[6]; -+ u16 seq_ctrl; -+ union { -+ struct { -+ u16 auth_alg; -+ u16 auth_transaction; -+ u16 status_code; -+ /* possibly followed by Challenge text */ -+ u8 variable[0]; -+ } auth; -+ struct { -+ u16 reason_code; -+ } deauth; -+ struct { -+ u16 capab_info; -+ u16 listen_interval; -+ /* followed by SSID and Supported rates */ -+ u8 variable[0]; -+ } assoc_req; -+ struct { -+ u16 capab_info; -+ u16 status_code; -+ u16 aid; -+ /* followed by Supported rates */ -+ u8 variable[0]; -+ } assoc_resp, reassoc_resp; -+ struct { -+ u16 capab_info; -+ u16 listen_interval; -+ u8 current_ap[6]; -+ /* followed by SSID and Supported rates */ -+ u8 variable[0]; -+ } reassoc_req; -+ struct { -+ u16 reason_code; -+ } disassoc; -+#if 0 -+ struct { -+ __le64 timestamp; -+ u16 beacon_int; -+ u16 capab_info; -+ /* followed by some of SSID, Supported rates, -+ * FH Params, DS Params, CF Params, IBSS Params, TIM */ -+ u8 variable[0]; -+ } beacon; -+ struct { -+ /* only variable items: SSID, Supported rates */ -+ u8 variable[0]; -+ } probe_req; -+ -+ struct { -+ __le64 timestamp; -+ u16 beacon_int; -+ u16 capab_info; -+ /* followed by some of SSID, Supported rates, -+ * FH Params, DS Params, CF Params, IBSS Params */ -+ u8 variable[0]; -+ } probe_resp; -+#endif -+ struct { -+ u8 category; -+ union { -+ struct { -+ u8 action_code; -+ u8 dialog_token; -+ u8 status_code; -+ u8 variable[0]; -+ } wme_action; -+ #if 0 -+ struct{ -+ u8 action_code; -+ u8 element_id; -+ u8 length; -+ struct ieee80211_channel_sw_ie sw_elem; -+ } chan_switch; -+ struct{ -+ u8 action_code; -+ u8 dialog_token; -+ u8 element_id; -+ u8 length; -+ struct ieee80211_msrment_ie msr_elem; -+ } measurement; -+ #endif -+ struct { -+ u8 action_code; -+ u8 dialog_token; -+ u16 capab; -+ u16 timeout; -+ u16 start_seq_num; -+ } addba_req; -+ struct { -+ u8 action_code; -+ u8 dialog_token; -+ u16 status; -+ u16 capab; -+ u16 timeout; -+ } addba_resp; -+ struct { -+ u8 action_code; -+ u16 params; -+ u16 reason_code; -+ } delba; -+ struct { -+ u8 action_code; -+ /* capab_info for open and confirm, -+ * reason for close -+ */ -+ u16 aux; -+ /* Followed in plink_confirm by status -+ * code, AID and supported rates, -+ * and directly by supported rates in -+ * plink_open and plink_close -+ */ -+ u8 variable[0]; -+ } plink_action; -+ struct { -+ u8 action_code; -+ u8 variable[0]; -+ } mesh_action; -+ } u; -+ } action; -+ } u; -+} ; -+ -+#pragma pack() -+ -+#endif -+ -+/* mgmt header + 1 byte category code */ -+#define IEEE80211_MIN_ACTION_SIZE FIELD_OFFSET(struct ieee80211_mgmt, u.action.u) -+ -+ -+ -+#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/if_ether.h linux-5.8/3rdparty/rtl8812au/include/if_ether.h -new file mode 100644 -index 000000000..a3007c4ab ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/if_ether.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/if_ether.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/if_ether.h +--- linux-5.11.4/3rdparty/rtl8812au/include/if_ether.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/if_ether.h 2021-03-07 18:16:17.087957613 +0200 @@ -0,0 +1,106 @@ +/****************************************************************************** + * @@ -387843,11 +384371,9 @@ index 000000000..a3007c4ab + + +#endif /* _LINUX_IF_ETHER_H */ -diff --git linux-5.8/3rdparty/rtl8812au/include/ip.h linux-5.8/3rdparty/rtl8812au/include/ip.h -new file mode 100644 -index 000000000..4feb98fb0 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/ip.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/ip.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/ip.h +--- linux-5.11.4/3rdparty/rtl8812au/include/ip.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/ip.h 2021-03-07 18:16:17.087957613 +0200 @@ -0,0 +1,135 @@ +/****************************************************************************** + * @@ -387984,11 +384510,9 @@ index 000000000..4feb98fb0 +}; + +#endif /* _LINUX_IP_H */ -diff --git linux-5.8/3rdparty/rtl8812au/include/linux/old_unused_rtl_wireless.h linux-5.8/3rdparty/rtl8812au/include/linux/old_unused_rtl_wireless.h -new file mode 100644 -index 000000000..c7f4a6c9b ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/linux/old_unused_rtl_wireless.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/linux/old_unused_rtl_wireless.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/linux/old_unused_rtl_wireless.h +--- linux-5.11.4/3rdparty/rtl8812au/include/linux/old_unused_rtl_wireless.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/linux/old_unused_rtl_wireless.h 2021-03-07 18:16:17.087957613 +0200 @@ -0,0 +1,87 @@ +/****************************************************************************** + * @@ -388077,11 +384601,9 @@ index 000000000..c7f4a6c9b +}; + +#endif /* _LINUX_WIRELESS_H */ -diff --git linux-5.8/3rdparty/rtl8812au/include/mlme_osdep.h linux-5.8/3rdparty/rtl8812au/include/mlme_osdep.h -new file mode 100644 -index 000000000..131eb0925 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/mlme_osdep.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/mlme_osdep.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/mlme_osdep.h +--- linux-5.11.4/3rdparty/rtl8812au/include/mlme_osdep.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/mlme_osdep.h 2021-03-07 18:16:17.087957613 +0200 @@ -0,0 +1,25 @@ +/****************************************************************************** + * @@ -388108,11 +384630,9 @@ index 000000000..131eb0925 +void rtw_reset_securitypriv(_adapter *adapter); + +#endif /* _MLME_OSDEP_H_ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/mp_custom_oid.h linux-5.8/3rdparty/rtl8812au/include/mp_custom_oid.h -new file mode 100644 -index 000000000..8ed14413c ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/mp_custom_oid.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/mp_custom_oid.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/mp_custom_oid.h +--- linux-5.11.4/3rdparty/rtl8812au/include/mp_custom_oid.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/mp_custom_oid.h 2021-03-07 18:16:17.087957613 +0200 @@ -0,0 +1,348 @@ +/****************************************************************************** + * @@ -388462,11 +384982,9 @@ index 000000000..8ed14413c +#define OID_RT_PRO_EFUSE_MAP 0xFF871217 /* Q, S */ + +#endif /* #ifndef __CUSTOM_OID_H */ -diff --git linux-5.8/3rdparty/rtl8812au/include/nic_spec.h linux-5.8/3rdparty/rtl8812au/include/nic_spec.h -new file mode 100644 -index 000000000..913ef9ba8 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/nic_spec.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/nic_spec.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/nic_spec.h +--- linux-5.11.4/3rdparty/rtl8812au/include/nic_spec.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/nic_spec.h 2021-03-07 18:16:17.087957613 +0200 @@ -0,0 +1,41 @@ +/****************************************************************************** + * @@ -388509,11 +385027,9 @@ index 000000000..913ef9ba8 + + +#endif /* __RTL8711_SPEC_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/osdep_intf.h linux-5.8/3rdparty/rtl8812au/include/osdep_intf.h -new file mode 100644 -index 000000000..7be08808d ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/osdep_intf.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/osdep_intf.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/osdep_intf.h +--- linux-5.11.4/3rdparty/rtl8812au/include/osdep_intf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/osdep_intf.h 2021-03-07 18:16:17.087957613 +0200 @@ -0,0 +1,167 @@ +/****************************************************************************** + * @@ -388682,11 +385198,973 @@ index 000000000..7be08808d +int rtw_resume_common(_adapter *padapter); + +#endif /* _OSDEP_INTF_H_ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/osdep_service.h linux-5.8/3rdparty/rtl8812au/include/osdep_service.h -new file mode 100644 -index 000000000..d7e375329 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/osdep_service.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/osdep_service_bsd.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/osdep_service_bsd.h +--- linux-5.11.4/3rdparty/rtl8812au/include/osdep_service_bsd.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/osdep_service_bsd.h 2021-03-07 18:16:17.087957613 +0200 +@@ -0,0 +1,756 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++#ifndef __OSDEP_BSD_SERVICE_H_ ++#define __OSDEP_BSD_SERVICE_H_ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include "usbdevs.h" ++ ++#define USB_DEBUG_VAR rum_debug ++#include ++ ++#if 1 //Baron porting from linux, it's all temp solution, needs to check again ++#include ++#include /* XXX for PCPU_GET */ ++// typedef struct semaphore _sema; ++ typedef struct sema _sema; ++// typedef spinlock_t _lock; ++ typedef struct mtx _lock; ++ typedef struct mtx _mutex; ++ typedef struct rtw_timer_list _timer; ++ struct list_head { ++ struct list_head *next, *prev; ++ }; ++ struct __queue { ++ struct list_head queue; ++ _lock lock; ++ }; ++ ++ typedef struct mbuf _pkt; ++ typedef struct mbuf _buffer; ++ ++ typedef struct __queue _queue; ++ typedef struct list_head _list; ++ typedef int _OS_STATUS; ++ //typedef u32 _irqL; ++ typedef unsigned long _irqL; ++ typedef struct ifnet * _nic_hdl; ++ ++ typedef pid_t _thread_hdl_; ++// typedef struct thread _thread_hdl_; ++ typedef void thread_return; ++ typedef void* thread_context; ++ ++ typedef void timer_hdl_return; ++ typedef void* timer_hdl_context; ++ typedef struct work_struct _workitem; ++ ++#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) ++/* emulate a modern version */ ++#define LINUX_VERSION_CODE KERNEL_VERSION(2, 6, 35) ++ ++#define WIRELESS_EXT -1 ++#define HZ hz ++#define spin_lock_irqsave mtx_lock_irqsave ++#define spin_lock_bh mtx_lock_irqsave ++#define mtx_lock_irqsave(lock, x) mtx_lock(lock)//{local_irq_save((x)); mtx_lock_spin((lock));} ++//#define IFT_RTW 0xf9 //ifnet allocate type for RTW ++#define free_netdev if_free ++#define LIST_CONTAINOR(ptr, type, member) \ ++ ((type *)((char *)(ptr)-(SIZE_T)(&((type *)0)->member))) ++#define container_of(p,t,n) (t*)((p)-&(((t*)0)->n)) ++/* ++ * Linux timers are emulated using FreeBSD callout functions ++ * (and taskqueue functionality). ++ * ++ * Currently no timer stats functionality. ++ * ++ * See (linux_compat) processes.c ++ * ++ */ ++struct rtw_timer_list { ++ struct callout callout; ++ void (*function)(void *); ++ void *arg; ++}; ++ ++struct workqueue_struct; ++struct work_struct; ++typedef void (*work_func_t)(struct work_struct *work); ++/* Values for the state of an item of work (work_struct) */ ++typedef enum work_state { ++ WORK_STATE_UNSET = 0, ++ WORK_STATE_CALLOUT_PENDING = 1, ++ WORK_STATE_TASK_PENDING = 2, ++ WORK_STATE_WORK_CANCELLED = 3 ++} work_state_t; ++ ++struct work_struct { ++ struct task task; /* FreeBSD task */ ++ work_state_t state; /* the pending or otherwise state of work. */ ++ work_func_t func; ++}; ++#define spin_unlock_irqrestore mtx_unlock_irqrestore ++#define spin_unlock_bh mtx_unlock_irqrestore ++#define mtx_unlock_irqrestore(lock,x) mtx_unlock(lock); ++extern void _rtw_spinlock_init(_lock *plock); ++ ++//modify private structure to match freebsd ++#define BITS_PER_LONG 32 ++union ktime { ++ s64 tv64; ++#if BITS_PER_LONG != 64 && !defined(CONFIG_KTIME_SCALAR) ++ struct { ++#ifdef __BIG_ENDIAN ++ s32 sec, nsec; ++#else ++ s32 nsec, sec; ++#endif ++ } tv; ++#endif ++}; ++#define kmemcheck_bitfield_begin(name) ++#define kmemcheck_bitfield_end(name) ++#define CHECKSUM_NONE 0 ++typedef unsigned char *sk_buff_data_t; ++typedef union ktime ktime_t; /* Kill this */ ++ ++void rtw_mtx_lock(_lock *plock); ++ ++void rtw_mtx_unlock(_lock *plock); ++ ++/** ++ * struct sk_buff - socket buffer ++ * @next: Next buffer in list ++ * @prev: Previous buffer in list ++ * @sk: Socket we are owned by ++ * @tstamp: Time we arrived ++ * @dev: Device we arrived on/are leaving by ++ * @transport_header: Transport layer header ++ * @network_header: Network layer header ++ * @mac_header: Link layer header ++ * @_skb_refdst: destination entry (with norefcount bit) ++ * @sp: the security path, used for xfrm ++ * @cb: Control buffer. Free for use by every layer. Put private vars here ++ * @len: Length of actual data ++ * @data_len: Data length ++ * @mac_len: Length of link layer header ++ * @hdr_len: writable header length of cloned skb ++ * @csum: Checksum (must include start/offset pair) ++ * @csum_start: Offset from skb->head where checksumming should start ++ * @csum_offset: Offset from csum_start where checksum should be stored ++ * @local_df: allow local fragmentation ++ * @cloned: Head may be cloned (check refcnt to be sure) ++ * @nohdr: Payload reference only, must not modify header ++ * @pkt_type: Packet class ++ * @fclone: skbuff clone status ++ * @ip_summed: Driver fed us an IP checksum ++ * @priority: Packet queueing priority ++ * @users: User count - see {datagram,tcp}.c ++ * @protocol: Packet protocol from driver ++ * @truesize: Buffer size ++ * @head: Head of buffer ++ * @data: Data head pointer ++ * @tail: Tail pointer ++ * @end: End pointer ++ * @destructor: Destruct function ++ * @mark: Generic packet mark ++ * @nfct: Associated connection, if any ++ * @ipvs_property: skbuff is owned by ipvs ++ * @peeked: this packet has been seen already, so stats have been ++ * done for it, don't do them again ++ * @nf_trace: netfilter packet trace flag ++ * @nfctinfo: Relationship of this skb to the connection ++ * @nfct_reasm: netfilter conntrack re-assembly pointer ++ * @nf_bridge: Saved data about a bridged frame - see br_netfilter.c ++ * @skb_iif: ifindex of device we arrived on ++ * @rxhash: the packet hash computed on receive ++ * @queue_mapping: Queue mapping for multiqueue devices ++ * @tc_index: Traffic control index ++ * @tc_verd: traffic control verdict ++ * @ndisc_nodetype: router type (from link layer) ++ * @dma_cookie: a cookie to one of several possible DMA operations ++ * done by skb DMA functions ++ * @secmark: security marking ++ * @vlan_tci: vlan tag control information ++ */ ++ ++struct sk_buff { ++ /* These two members must be first. */ ++ struct sk_buff *next; ++ struct sk_buff *prev; ++ ++ ktime_t tstamp; ++ ++ struct sock *sk; ++ //struct net_device *dev; ++ struct ifnet *dev; ++ ++ /* ++ * This is the control buffer. It is free to use for every ++ * layer. Please put your private variables there. If you ++ * want to keep them across layers you have to do a skb_clone() ++ * first. This is owned by whoever has the skb queued ATM. ++ */ ++ char cb[48] __aligned(8); ++ ++ unsigned long _skb_refdst; ++#ifdef CONFIG_XFRM ++ struct sec_path *sp; ++#endif ++ unsigned int len, ++ data_len; ++ u16 mac_len, ++ hdr_len; ++ union { ++ u32 csum; ++ struct { ++ u16 csum_start; ++ u16 csum_offset; ++ }smbol2; ++ }smbol1; ++ u32 priority; ++ kmemcheck_bitfield_begin(flags1); ++ u8 local_df:1, ++ cloned:1, ++ ip_summed:2, ++ nohdr:1, ++ nfctinfo:3; ++ u8 pkt_type:3, ++ fclone:2, ++ ipvs_property:1, ++ peeked:1, ++ nf_trace:1; ++ kmemcheck_bitfield_end(flags1); ++ u16 protocol; ++ ++ void (*destructor)(struct sk_buff *skb); ++#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) ++ struct nf_conntrack *nfct; ++ struct sk_buff *nfct_reasm; ++#endif ++#ifdef CONFIG_BRIDGE_NETFILTER ++ struct nf_bridge_info *nf_bridge; ++#endif ++ ++ int skb_iif; ++#ifdef CONFIG_NET_SCHED ++ u16 tc_index; /* traffic control index */ ++#ifdef CONFIG_NET_CLS_ACT ++ u16 tc_verd; /* traffic control verdict */ ++#endif ++#endif ++ ++ u32 rxhash; ++ ++ kmemcheck_bitfield_begin(flags2); ++ u16 queue_mapping:16; ++#ifdef CONFIG_IPV6_NDISC_NODETYPE ++ u8 ndisc_nodetype:2, ++ deliver_no_wcard:1; ++#else ++ u8 deliver_no_wcard:1; ++#endif ++ kmemcheck_bitfield_end(flags2); ++ ++ /* 0/14 bit hole */ ++ ++#ifdef CONFIG_NET_DMA ++ dma_cookie_t dma_cookie; ++#endif ++#ifdef CONFIG_NETWORK_SECMARK ++ u32 secmark; ++#endif ++ union { ++ u32 mark; ++ u32 dropcount; ++ }symbol3; ++ ++ u16 vlan_tci; ++ ++ sk_buff_data_t transport_header; ++ sk_buff_data_t network_header; ++ sk_buff_data_t mac_header; ++ /* These elements must be at the end, see alloc_skb() for details. */ ++ sk_buff_data_t tail; ++ sk_buff_data_t end; ++ unsigned char *head, ++ *data; ++ unsigned int truesize; ++ atomic_t users; ++}; ++struct sk_buff_head { ++ /* These two members must be first. */ ++ struct sk_buff *next; ++ struct sk_buff *prev; ++ ++ u32 qlen; ++ _lock lock; ++}; ++#define skb_tail_pointer(skb) skb->tail ++static inline unsigned char *skb_put(struct sk_buff *skb, unsigned int len) ++{ ++ unsigned char *tmp = skb_tail_pointer(skb); ++ //SKB_LINEAR_ASSERT(skb); ++ skb->tail += len; ++ skb->len += len; ++ return tmp; ++} ++ ++static inline unsigned char *__skb_pull(struct sk_buff *skb, unsigned int len) ++{ ++ skb->len -= len; ++ if(skb->len < skb->data_len) ++ printf("%s(),%d,error!\n",__FUNCTION__,__LINE__); ++ return skb->data += len; ++} ++static inline unsigned char *skb_pull(struct sk_buff *skb, unsigned int len) ++{ ++ #ifdef PLATFORM_FREEBSD ++ return __skb_pull(skb, len); ++ #else ++ return unlikely(len > skb->len) ? NULL : __skb_pull(skb, len); ++ #endif //PLATFORM_FREEBSD ++} ++static inline u32 skb_queue_len(const struct sk_buff_head *list_) ++{ ++ return list_->qlen; ++} ++static inline void __skb_insert(struct sk_buff *newsk, ++ struct sk_buff *prev, struct sk_buff *next, ++ struct sk_buff_head *list) ++{ ++ newsk->next = next; ++ newsk->prev = prev; ++ next->prev = prev->next = newsk; ++ list->qlen++; ++} ++static inline void __skb_queue_before(struct sk_buff_head *list, ++ struct sk_buff *next, ++ struct sk_buff *newsk) ++{ ++ __skb_insert(newsk, next->prev, next, list); ++} ++static inline void skb_queue_tail(struct sk_buff_head *list, ++ struct sk_buff *newsk) ++{ ++ mtx_lock(&list->lock); ++ __skb_queue_before(list, (struct sk_buff *)list, newsk); ++ mtx_unlock(&list->lock); ++} ++static inline struct sk_buff *skb_peek(struct sk_buff_head *list_) ++{ ++ struct sk_buff *list = ((struct sk_buff *)list_)->next; ++ if (list == (struct sk_buff *)list_) ++ list = NULL; ++ return list; ++} ++static inline void __skb_unlink(struct sk_buff *skb, struct sk_buff_head *list) ++{ ++ struct sk_buff *next, *prev; ++ ++ list->qlen--; ++ next = skb->next; ++ prev = skb->prev; ++ skb->next = skb->prev = NULL; ++ next->prev = prev; ++ prev->next = next; ++} ++ ++static inline struct sk_buff *skb_dequeue(struct sk_buff_head *list) ++{ ++ mtx_lock(&list->lock); ++ ++ struct sk_buff *skb = skb_peek(list); ++ if (skb) ++ __skb_unlink(skb, list); ++ ++ mtx_unlock(&list->lock); ++ ++ return skb; ++} ++static inline void skb_reserve(struct sk_buff *skb, int len) ++{ ++ skb->data += len; ++ skb->tail += len; ++} ++static inline void __skb_queue_head_init(struct sk_buff_head *list) ++{ ++ list->prev = list->next = (struct sk_buff *)list; ++ list->qlen = 0; ++} ++/* ++ * This function creates a split out lock class for each invocation; ++ * this is needed for now since a whole lot of users of the skb-queue ++ * infrastructure in drivers have different locking usage (in hardirq) ++ * than the networking core (in softirq only). In the long run either the ++ * network layer or drivers should need annotation to consolidate the ++ * main types of usage into 3 classes. ++ */ ++static inline void skb_queue_head_init(struct sk_buff_head *list) ++{ ++ _rtw_spinlock_init(&list->lock); ++ __skb_queue_head_init(list); ++} ++unsigned long copy_from_user(void *to, const void *from, unsigned long n); ++unsigned long copy_to_user(void *to, const void *from, unsigned long n); ++struct sk_buff * dev_alloc_skb(unsigned int size); ++struct sk_buff *skb_clone(const struct sk_buff *skb); ++void dev_kfree_skb_any(struct sk_buff *skb); ++#endif //Baron porting from linux, it's all temp solution, needs to check again ++ ++ ++#if 1 // kenny add Linux compatibility code for Linux USB driver ++#include ++ ++#define __init // __attribute ((constructor)) ++#define __exit // __attribute ((destructor)) ++ ++/* ++ * Definitions for module_init and module_exit macros. ++ * ++ * These macros will use the SYSINIT framework to call a specified ++ * function (with no arguments) on module loading or unloading. ++ * ++ */ ++ ++void module_init_exit_wrapper(void *arg); ++ ++#define module_init(initfn) \ ++ SYSINIT(mod_init_ ## initfn, \ ++ SI_SUB_KLD, SI_ORDER_FIRST, \ ++ module_init_exit_wrapper, initfn) ++ ++#define module_exit(exitfn) \ ++ SYSUNINIT(mod_exit_ ## exitfn, \ ++ SI_SUB_KLD, SI_ORDER_ANY, \ ++ module_init_exit_wrapper, exitfn) ++ ++/* ++ * The usb_register and usb_deregister functions are used to register ++ * usb drivers with the usb subsystem. ++ */ ++int usb_register(struct usb_driver *driver); ++int usb_deregister(struct usb_driver *driver); ++ ++/* ++ * usb_get_dev and usb_put_dev - increment/decrement the reference count ++ * of the usb device structure. ++ * ++ * Original body of usb_get_dev: ++ * ++ * if (dev) ++ * get_device(&dev->dev); ++ * return dev; ++ * ++ * Reference counts are not currently used in this compatibility ++ * layer. So these functions will do nothing. ++ */ ++static inline struct usb_device * ++usb_get_dev(struct usb_device *dev) ++{ ++ return dev; ++} ++ ++static inline void ++usb_put_dev(struct usb_device *dev) ++{ ++ return; ++} ++ ++ ++// rtw_usb_compat_linux ++int rtw_usb_submit_urb(struct urb *urb, uint16_t mem_flags); ++int rtw_usb_unlink_urb(struct urb *urb); ++int rtw_usb_clear_halt(struct usb_device *dev, struct usb_host_endpoint *uhe); ++int rtw_usb_control_msg(struct usb_device *dev, struct usb_host_endpoint *uhe, ++ uint8_t request, uint8_t requesttype, ++ uint16_t value, uint16_t index, void *data, ++ uint16_t size, usb_timeout_t timeout); ++int rtw_usb_set_interface(struct usb_device *dev, uint8_t iface_no, uint8_t alt_index); ++int rtw_usb_setup_endpoint(struct usb_device *dev, ++ struct usb_host_endpoint *uhe, usb_size_t bufsize); ++struct urb *rtw_usb_alloc_urb(uint16_t iso_packets, uint16_t mem_flags); ++struct usb_host_endpoint *rtw_usb_find_host_endpoint(struct usb_device *dev, uint8_t type, uint8_t ep); ++struct usb_host_interface *rtw_usb_altnum_to_altsetting(const struct usb_interface *intf, uint8_t alt_index); ++struct usb_interface *rtw_usb_ifnum_to_if(struct usb_device *dev, uint8_t iface_no); ++void *rtw_usbd_get_intfdata(struct usb_interface *intf); ++void rtw_usb_linux_register(void *arg); ++void rtw_usb_linux_deregister(void *arg); ++void rtw_usb_linux_free_device(struct usb_device *dev); ++void rtw_usb_free_urb(struct urb *urb); ++void rtw_usb_init_urb(struct urb *urb); ++void rtw_usb_kill_urb(struct urb *urb); ++void rtw_usb_set_intfdata(struct usb_interface *intf, void *data); ++void rtw_usb_fill_bulk_urb(struct urb *urb, struct usb_device *udev, ++ struct usb_host_endpoint *uhe, void *buf, ++ int length, usb_complete_t callback, void *arg); ++int rtw_usb_bulk_msg(struct usb_device *udev, struct usb_host_endpoint *uhe, ++ void *data, int len, uint16_t *pactlen, usb_timeout_t timeout); ++void *usb_get_intfdata(struct usb_interface *intf); ++int usb_linux_init_endpoints(struct usb_device *udev); ++ ++ ++ ++typedef struct urb * PURB; ++ ++typedef unsigned gfp_t; ++#define __GFP_WAIT ((gfp_t)0x10u) /* Can wait and reschedule? */ ++#define __GFP_HIGH ((gfp_t)0x20u) /* Should access emergency pools? */ ++#define __GFP_IO ((gfp_t)0x40u) /* Can start physical IO? */ ++#define __GFP_FS ((gfp_t)0x80u) /* Can call down to low-level FS? */ ++#define __GFP_COLD ((gfp_t)0x100u) /* Cache-cold page required */ ++#define __GFP_NOWARN ((gfp_t)0x200u) /* Suppress page allocation failure warning */ ++#define __GFP_REPEAT ((gfp_t)0x400u) /* Retry the allocation. Might fail */ ++#define __GFP_NOFAIL ((gfp_t)0x800u) /* Retry for ever. Cannot fail */ ++#define __GFP_NORETRY ((gfp_t)0x1000u)/* Do not retry. Might fail */ ++#define __GFP_NO_GROW ((gfp_t)0x2000u)/* Slab internal usage */ ++#define __GFP_COMP ((gfp_t)0x4000u)/* Add compound page metadata */ ++#define __GFP_ZERO ((gfp_t)0x8000u)/* Return zeroed page on success */ ++#define __GFP_NOMEMALLOC ((gfp_t)0x10000u) /* Don't use emergency reserves */ ++#define __GFP_HARDWALL ((gfp_t)0x20000u) /* Enforce hardwall cpuset memory allocs */ ++ ++/* This equals 0, but use constants in case they ever change */ ++#define GFP_NOWAIT (GFP_ATOMIC & ~__GFP_HIGH) ++/* GFP_ATOMIC means both !wait (__GFP_WAIT not set) and use emergency pool */ ++#define GFP_ATOMIC (__GFP_HIGH) ++#define GFP_NOIO (__GFP_WAIT) ++#define GFP_NOFS (__GFP_WAIT | __GFP_IO) ++#define GFP_KERNEL (__GFP_WAIT | __GFP_IO | __GFP_FS) ++#define GFP_USER (__GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL) ++#define GFP_HIGHUSER (__GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL | \ ++ __GFP_HIGHMEM) ++ ++ ++#endif // kenny add Linux compatibility code for Linux USB ++ ++__inline static _list *get_next(_list *list) ++{ ++ return list->next; ++} ++ ++__inline static _list *get_list_head(_queue *queue) ++{ ++ return (&(queue->queue)); ++} ++ ++ ++#define LIST_CONTAINOR(ptr, type, member) \ ++ ((type *)((char *)(ptr)-(SIZE_T)(&((type *)0)->member))) ++ ++ ++__inline static void _enter_critical(_lock *plock, _irqL *pirqL) ++{ ++ spin_lock_irqsave(plock, *pirqL); ++} ++ ++__inline static void _exit_critical(_lock *plock, _irqL *pirqL) ++{ ++ spin_unlock_irqrestore(plock, *pirqL); ++} ++ ++__inline static void _enter_critical_ex(_lock *plock, _irqL *pirqL) ++{ ++ spin_lock_irqsave(plock, *pirqL); ++} ++ ++__inline static void _exit_critical_ex(_lock *plock, _irqL *pirqL) ++{ ++ spin_unlock_irqrestore(plock, *pirqL); ++} ++ ++__inline static void _enter_critical_bh(_lock *plock, _irqL *pirqL) ++{ ++ spin_lock_bh(plock, *pirqL); ++} ++ ++__inline static void _exit_critical_bh(_lock *plock, _irqL *pirqL) ++{ ++ spin_unlock_bh(plock, *pirqL); ++} ++ ++__inline static void _enter_critical_mutex(_mutex *pmutex, _irqL *pirqL) ++{ ++ ++ mtx_lock(pmutex); ++ ++} ++ ++ ++__inline static void _exit_critical_mutex(_mutex *pmutex, _irqL *pirqL) ++{ ++ ++ mtx_unlock(pmutex); ++ ++} ++static inline void __list_del(struct list_head * prev, struct list_head * next) ++{ ++ next->prev = prev; ++ prev->next = next; ++} ++static inline void INIT_LIST_HEAD(struct list_head *list) ++{ ++ list->next = list; ++ list->prev = list; ++} ++__inline static void rtw_list_delete(_list *plist) ++{ ++ __list_del(plist->prev, plist->next); ++ INIT_LIST_HEAD(plist); ++} ++ ++static inline void timer_hdl(void *ctx) ++{ ++ _timer *timer = (_timer *)ctx; ++ ++ rtw_mtx_lock(NULL); ++ if (callout_pending(&timer->callout)) { ++ /* callout was reset */ ++ rtw_mtx_unlock(NULL); ++ return; ++ } ++ ++ if (!callout_active(&timer->callout)) { ++ /* callout was stopped */ ++ rtw_mtx_unlock(NULL); ++ return; ++ } ++ ++ callout_deactivate(&timer->callout); ++ ++ timer->function(timer->arg); ++ ++ rtw_mtx_unlock(NULL); ++} ++ ++static inline void _init_timer(_timer *ptimer, _nic_hdl padapter, void *pfunc, void *cntx) ++{ ++ ptimer->function = pfunc; ++ ptimer->arg = cntx; ++ callout_init(&ptimer->callout, CALLOUT_MPSAFE); ++} ++ ++__inline static void _set_timer(_timer *ptimer,u32 delay_time) ++{ ++ if (ptimer->function && ptimer->arg) { ++ rtw_mtx_lock(NULL); ++ callout_reset(&ptimer->callout, delay_time, timer_hdl, ptimer); ++ rtw_mtx_unlock(NULL); ++ } ++} ++ ++__inline static void _cancel_timer(_timer *ptimer,u8 *bcancelled) ++{ ++ rtw_mtx_lock(NULL); ++ callout_drain(&ptimer->callout); ++ rtw_mtx_unlock(NULL); ++ *bcancelled = 1; /* assume an pending timer to be canceled */ ++} ++ ++__inline static void _init_workitem(_workitem *pwork, void *pfunc, PVOID cntx) ++{ ++ printf("%s Not implement yet! \n",__FUNCTION__); ++} ++ ++__inline static void _set_workitem(_workitem *pwork) ++{ ++ printf("%s Not implement yet! \n",__FUNCTION__); ++// schedule_work(pwork); ++} ++ ++// ++// Global Mutex: can only be used at PASSIVE level. ++// ++ ++#define ACQUIRE_GLOBAL_MUTEX(_MutexCounter) \ ++{ \ ++} ++ ++#define RELEASE_GLOBAL_MUTEX(_MutexCounter) \ ++{ \ ++} ++ ++#define ATOMIC_INIT(i) { (i) } ++ ++static __inline void thread_enter(char *name); ++ ++//Atomic integer operations ++typedef uint32_t ATOMIC_T ; ++ ++#define rtw_netdev_priv(netdev) (((struct ifnet *)netdev)->if_softc) ++ ++#define rtw_free_netdev(netdev) if_free((netdev)) ++ ++#define NDEV_FMT "%s" ++#define NDEV_ARG(ndev) "" ++#define ADPT_FMT "%s" ++#define ADPT_ARG(adapter) "" ++#define FUNC_NDEV_FMT "%s" ++#define FUNC_NDEV_ARG(ndev) __func__ ++#define FUNC_ADPT_FMT "%s" ++#define FUNC_ADPT_ARG(adapter) __func__ ++ ++#define STRUCT_PACKED ++ ++#endif ++ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/osdep_service_ce.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/osdep_service_ce.h +--- linux-5.11.4/3rdparty/rtl8812au/include/osdep_service_ce.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/osdep_service_ce.h 2021-03-07 18:16:17.087957613 +0200 +@@ -0,0 +1,200 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++ ++#ifndef __OSDEP_CE_SERVICE_H_ ++#define __OSDEP_CE_SERVICE_H_ ++ ++ ++#include ++#include ++ ++#ifdef CONFIG_SDIO_HCI ++#include "SDCardDDK.h" ++#endif ++ ++#ifdef CONFIG_USB_HCI ++#include ++#endif ++ ++typedef HANDLE _sema; ++typedef LIST_ENTRY _list; ++typedef NDIS_STATUS _OS_STATUS; ++ ++typedef NDIS_SPIN_LOCK _lock; ++ ++typedef HANDLE _rwlock; //Mutex ++ ++typedef u32 _irqL; ++ ++typedef NDIS_HANDLE _nic_hdl; ++ ++struct rtw_timer_list { ++ NDIS_MINIPORT_TIMER ndis_timer; ++ void (*function)(void *); ++ void *arg; ++}; ++ ++struct __queue { ++ LIST_ENTRY queue; ++ _lock lock; ++}; ++ ++typedef NDIS_PACKET _pkt; ++typedef NDIS_BUFFER _buffer; ++typedef struct __queue _queue; ++ ++typedef HANDLE _thread_hdl_; ++typedef DWORD thread_return; ++typedef void* thread_context; ++typedef NDIS_WORK_ITEM _workitem; ++ ++ ++ ++#define SEMA_UPBND (0x7FFFFFFF) //8192 ++ ++__inline static _list *get_prev(_list *list) ++{ ++ return list->Blink; ++} ++ ++__inline static _list *get_next(_list *list) ++{ ++ return list->Flink; ++} ++ ++__inline static _list *get_list_head(_queue *queue) ++{ ++ return (&(queue->queue)); ++} ++ ++#define LIST_CONTAINOR(ptr, type, member) CONTAINING_RECORD(ptr, type, member) ++ ++__inline static void _enter_critical(_lock *plock, _irqL *pirqL) ++{ ++ NdisAcquireSpinLock(plock); ++} ++ ++__inline static void _exit_critical(_lock *plock, _irqL *pirqL) ++{ ++ NdisReleaseSpinLock(plock); ++} ++ ++__inline static _enter_critical_ex(_lock *plock, _irqL *pirqL) ++{ ++ NdisDprAcquireSpinLock(plock); ++} ++ ++__inline static _exit_critical_ex(_lock *plock, _irqL *pirqL) ++{ ++ NdisDprReleaseSpinLock(plock); ++} ++ ++ ++__inline static void _enter_hwio_critical(_rwlock *prwlock, _irqL *pirqL) ++{ ++ WaitForSingleObject(*prwlock, INFINITE ); ++ ++} ++ ++__inline static void _exit_hwio_critical(_rwlock *prwlock, _irqL *pirqL) ++{ ++ ReleaseMutex(*prwlock); ++} ++ ++__inline static void rtw_list_delete(_list *plist) ++{ ++ RemoveEntryList(plist); ++ InitializeListHead(plist); ++} ++ ++static inline void timer_hdl( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ _timer *timer = (_timer *)FunctionContext; ++ ++ timer->function(timer->arg); ++} ++ ++static inline void _init_timer(_timer *ptimer, _nic_hdl nic_hdl, void *pfunc, void *cntx) ++{ ++ ptimer->function = pfunc; ++ ptimer->arg = cntx; ++ NdisMInitializeTimer(&ptimer->ndis_timer, nic_hdl, timer_hdl, ptimer); ++} ++ ++static inline void _set_timer(_timer *ptimer, u32 delay_time) ++{ ++ NdisMSetTimer(ptimer, delay_time); ++} ++ ++static inline void _cancel_timer(_timer *ptimer, u8 *bcancelled) ++{ ++ NdisMCancelTimer(ptimer, bcancelled); ++} ++ ++__inline static void _init_workitem(_workitem *pwork, void *pfunc, PVOID cntx) ++{ ++ ++ NdisInitializeWorkItem(pwork, pfunc, cntx); ++} ++ ++__inline static void _set_workitem(_workitem *pwork) ++{ ++ NdisScheduleWorkItem(pwork); ++} ++ ++#define ATOMIC_INIT(i) { (i) } ++ ++// ++// Global Mutex: can only be used at PASSIVE level. ++// ++ ++#define ACQUIRE_GLOBAL_MUTEX(_MutexCounter) \ ++{ \ ++ while (NdisInterlockedIncrement((PULONG)&(_MutexCounter)) != 1)\ ++ { \ ++ NdisInterlockedDecrement((PULONG)&(_MutexCounter)); \ ++ NdisMSleep(10000); \ ++ } \ ++} ++ ++#define RELEASE_GLOBAL_MUTEX(_MutexCounter) \ ++{ \ ++ NdisInterlockedDecrement((PULONG)&(_MutexCounter)); \ ++} ++ ++// limitation of path length ++#define PATH_LENGTH_MAX MAX_PATH ++ ++//Atomic integer operations ++#define ATOMIC_T LONG ++ ++#define NDEV_FMT "%s" ++#define NDEV_ARG(ndev) "" ++#define ADPT_FMT "%s" ++#define ADPT_ARG(adapter) "" ++#define FUNC_NDEV_FMT "%s" ++#define FUNC_NDEV_ARG(ndev) __func__ ++#define FUNC_ADPT_FMT "%s" ++#define FUNC_ADPT_ARG(adapter) __func__ ++ ++#define STRUCT_PACKED ++ ++ ++#endif ++ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/osdep_service.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/osdep_service.h +--- linux-5.11.4/3rdparty/rtl8812au/include/osdep_service.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/osdep_service.h 2021-03-07 18:16:17.087957613 +0200 @@ -0,0 +1,804 @@ +/****************************************************************************** + * @@ -389492,979 +386970,9 @@ index 000000000..d7e375329 +#endif /* !PLATFORM_LINUX */ + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/osdep_service_bsd.h linux-5.8/3rdparty/rtl8812au/include/osdep_service_bsd.h -new file mode 100644 -index 000000000..4773f05fd ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/osdep_service_bsd.h -@@ -0,0 +1,756 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+#ifndef __OSDEP_BSD_SERVICE_H_ -+#define __OSDEP_BSD_SERVICE_H_ -+ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include "usbdevs.h" -+ -+#define USB_DEBUG_VAR rum_debug -+#include -+ -+#if 1 //Baron porting from linux, it's all temp solution, needs to check again -+#include -+#include /* XXX for PCPU_GET */ -+// typedef struct semaphore _sema; -+ typedef struct sema _sema; -+// typedef spinlock_t _lock; -+ typedef struct mtx _lock; -+ typedef struct mtx _mutex; -+ typedef struct rtw_timer_list _timer; -+ struct list_head { -+ struct list_head *next, *prev; -+ }; -+ struct __queue { -+ struct list_head queue; -+ _lock lock; -+ }; -+ -+ typedef struct mbuf _pkt; -+ typedef struct mbuf _buffer; -+ -+ typedef struct __queue _queue; -+ typedef struct list_head _list; -+ typedef int _OS_STATUS; -+ //typedef u32 _irqL; -+ typedef unsigned long _irqL; -+ typedef struct ifnet * _nic_hdl; -+ -+ typedef pid_t _thread_hdl_; -+// typedef struct thread _thread_hdl_; -+ typedef void thread_return; -+ typedef void* thread_context; -+ -+ typedef void timer_hdl_return; -+ typedef void* timer_hdl_context; -+ typedef struct work_struct _workitem; -+ -+#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) -+/* emulate a modern version */ -+#define LINUX_VERSION_CODE KERNEL_VERSION(2, 6, 35) -+ -+#define WIRELESS_EXT -1 -+#define HZ hz -+#define spin_lock_irqsave mtx_lock_irqsave -+#define spin_lock_bh mtx_lock_irqsave -+#define mtx_lock_irqsave(lock, x) mtx_lock(lock)//{local_irq_save((x)); mtx_lock_spin((lock));} -+//#define IFT_RTW 0xf9 //ifnet allocate type for RTW -+#define free_netdev if_free -+#define LIST_CONTAINOR(ptr, type, member) \ -+ ((type *)((char *)(ptr)-(SIZE_T)(&((type *)0)->member))) -+#define container_of(p,t,n) (t*)((p)-&(((t*)0)->n)) -+/* -+ * Linux timers are emulated using FreeBSD callout functions -+ * (and taskqueue functionality). -+ * -+ * Currently no timer stats functionality. -+ * -+ * See (linux_compat) processes.c -+ * -+ */ -+struct rtw_timer_list { -+ struct callout callout; -+ void (*function)(void *); -+ void *arg; -+}; -+ -+struct workqueue_struct; -+struct work_struct; -+typedef void (*work_func_t)(struct work_struct *work); -+/* Values for the state of an item of work (work_struct) */ -+typedef enum work_state { -+ WORK_STATE_UNSET = 0, -+ WORK_STATE_CALLOUT_PENDING = 1, -+ WORK_STATE_TASK_PENDING = 2, -+ WORK_STATE_WORK_CANCELLED = 3 -+} work_state_t; -+ -+struct work_struct { -+ struct task task; /* FreeBSD task */ -+ work_state_t state; /* the pending or otherwise state of work. */ -+ work_func_t func; -+}; -+#define spin_unlock_irqrestore mtx_unlock_irqrestore -+#define spin_unlock_bh mtx_unlock_irqrestore -+#define mtx_unlock_irqrestore(lock,x) mtx_unlock(lock); -+extern void _rtw_spinlock_init(_lock *plock); -+ -+//modify private structure to match freebsd -+#define BITS_PER_LONG 32 -+union ktime { -+ s64 tv64; -+#if BITS_PER_LONG != 64 && !defined(CONFIG_KTIME_SCALAR) -+ struct { -+#ifdef __BIG_ENDIAN -+ s32 sec, nsec; -+#else -+ s32 nsec, sec; -+#endif -+ } tv; -+#endif -+}; -+#define kmemcheck_bitfield_begin(name) -+#define kmemcheck_bitfield_end(name) -+#define CHECKSUM_NONE 0 -+typedef unsigned char *sk_buff_data_t; -+typedef union ktime ktime_t; /* Kill this */ -+ -+void rtw_mtx_lock(_lock *plock); -+ -+void rtw_mtx_unlock(_lock *plock); -+ -+/** -+ * struct sk_buff - socket buffer -+ * @next: Next buffer in list -+ * @prev: Previous buffer in list -+ * @sk: Socket we are owned by -+ * @tstamp: Time we arrived -+ * @dev: Device we arrived on/are leaving by -+ * @transport_header: Transport layer header -+ * @network_header: Network layer header -+ * @mac_header: Link layer header -+ * @_skb_refdst: destination entry (with norefcount bit) -+ * @sp: the security path, used for xfrm -+ * @cb: Control buffer. Free for use by every layer. Put private vars here -+ * @len: Length of actual data -+ * @data_len: Data length -+ * @mac_len: Length of link layer header -+ * @hdr_len: writable header length of cloned skb -+ * @csum: Checksum (must include start/offset pair) -+ * @csum_start: Offset from skb->head where checksumming should start -+ * @csum_offset: Offset from csum_start where checksum should be stored -+ * @local_df: allow local fragmentation -+ * @cloned: Head may be cloned (check refcnt to be sure) -+ * @nohdr: Payload reference only, must not modify header -+ * @pkt_type: Packet class -+ * @fclone: skbuff clone status -+ * @ip_summed: Driver fed us an IP checksum -+ * @priority: Packet queueing priority -+ * @users: User count - see {datagram,tcp}.c -+ * @protocol: Packet protocol from driver -+ * @truesize: Buffer size -+ * @head: Head of buffer -+ * @data: Data head pointer -+ * @tail: Tail pointer -+ * @end: End pointer -+ * @destructor: Destruct function -+ * @mark: Generic packet mark -+ * @nfct: Associated connection, if any -+ * @ipvs_property: skbuff is owned by ipvs -+ * @peeked: this packet has been seen already, so stats have been -+ * done for it, don't do them again -+ * @nf_trace: netfilter packet trace flag -+ * @nfctinfo: Relationship of this skb to the connection -+ * @nfct_reasm: netfilter conntrack re-assembly pointer -+ * @nf_bridge: Saved data about a bridged frame - see br_netfilter.c -+ * @skb_iif: ifindex of device we arrived on -+ * @rxhash: the packet hash computed on receive -+ * @queue_mapping: Queue mapping for multiqueue devices -+ * @tc_index: Traffic control index -+ * @tc_verd: traffic control verdict -+ * @ndisc_nodetype: router type (from link layer) -+ * @dma_cookie: a cookie to one of several possible DMA operations -+ * done by skb DMA functions -+ * @secmark: security marking -+ * @vlan_tci: vlan tag control information -+ */ -+ -+struct sk_buff { -+ /* These two members must be first. */ -+ struct sk_buff *next; -+ struct sk_buff *prev; -+ -+ ktime_t tstamp; -+ -+ struct sock *sk; -+ //struct net_device *dev; -+ struct ifnet *dev; -+ -+ /* -+ * This is the control buffer. It is free to use for every -+ * layer. Please put your private variables there. If you -+ * want to keep them across layers you have to do a skb_clone() -+ * first. This is owned by whoever has the skb queued ATM. -+ */ -+ char cb[48] __aligned(8); -+ -+ unsigned long _skb_refdst; -+#ifdef CONFIG_XFRM -+ struct sec_path *sp; -+#endif -+ unsigned int len, -+ data_len; -+ u16 mac_len, -+ hdr_len; -+ union { -+ u32 csum; -+ struct { -+ u16 csum_start; -+ u16 csum_offset; -+ }smbol2; -+ }smbol1; -+ u32 priority; -+ kmemcheck_bitfield_begin(flags1); -+ u8 local_df:1, -+ cloned:1, -+ ip_summed:2, -+ nohdr:1, -+ nfctinfo:3; -+ u8 pkt_type:3, -+ fclone:2, -+ ipvs_property:1, -+ peeked:1, -+ nf_trace:1; -+ kmemcheck_bitfield_end(flags1); -+ u16 protocol; -+ -+ void (*destructor)(struct sk_buff *skb); -+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) -+ struct nf_conntrack *nfct; -+ struct sk_buff *nfct_reasm; -+#endif -+#ifdef CONFIG_BRIDGE_NETFILTER -+ struct nf_bridge_info *nf_bridge; -+#endif -+ -+ int skb_iif; -+#ifdef CONFIG_NET_SCHED -+ u16 tc_index; /* traffic control index */ -+#ifdef CONFIG_NET_CLS_ACT -+ u16 tc_verd; /* traffic control verdict */ -+#endif -+#endif -+ -+ u32 rxhash; -+ -+ kmemcheck_bitfield_begin(flags2); -+ u16 queue_mapping:16; -+#ifdef CONFIG_IPV6_NDISC_NODETYPE -+ u8 ndisc_nodetype:2, -+ deliver_no_wcard:1; -+#else -+ u8 deliver_no_wcard:1; -+#endif -+ kmemcheck_bitfield_end(flags2); -+ -+ /* 0/14 bit hole */ -+ -+#ifdef CONFIG_NET_DMA -+ dma_cookie_t dma_cookie; -+#endif -+#ifdef CONFIG_NETWORK_SECMARK -+ u32 secmark; -+#endif -+ union { -+ u32 mark; -+ u32 dropcount; -+ }symbol3; -+ -+ u16 vlan_tci; -+ -+ sk_buff_data_t transport_header; -+ sk_buff_data_t network_header; -+ sk_buff_data_t mac_header; -+ /* These elements must be at the end, see alloc_skb() for details. */ -+ sk_buff_data_t tail; -+ sk_buff_data_t end; -+ unsigned char *head, -+ *data; -+ unsigned int truesize; -+ atomic_t users; -+}; -+struct sk_buff_head { -+ /* These two members must be first. */ -+ struct sk_buff *next; -+ struct sk_buff *prev; -+ -+ u32 qlen; -+ _lock lock; -+}; -+#define skb_tail_pointer(skb) skb->tail -+static inline unsigned char *skb_put(struct sk_buff *skb, unsigned int len) -+{ -+ unsigned char *tmp = skb_tail_pointer(skb); -+ //SKB_LINEAR_ASSERT(skb); -+ skb->tail += len; -+ skb->len += len; -+ return tmp; -+} -+ -+static inline unsigned char *__skb_pull(struct sk_buff *skb, unsigned int len) -+{ -+ skb->len -= len; -+ if(skb->len < skb->data_len) -+ printf("%s(),%d,error!\n",__FUNCTION__,__LINE__); -+ return skb->data += len; -+} -+static inline unsigned char *skb_pull(struct sk_buff *skb, unsigned int len) -+{ -+ #ifdef PLATFORM_FREEBSD -+ return __skb_pull(skb, len); -+ #else -+ return unlikely(len > skb->len) ? NULL : __skb_pull(skb, len); -+ #endif //PLATFORM_FREEBSD -+} -+static inline u32 skb_queue_len(const struct sk_buff_head *list_) -+{ -+ return list_->qlen; -+} -+static inline void __skb_insert(struct sk_buff *newsk, -+ struct sk_buff *prev, struct sk_buff *next, -+ struct sk_buff_head *list) -+{ -+ newsk->next = next; -+ newsk->prev = prev; -+ next->prev = prev->next = newsk; -+ list->qlen++; -+} -+static inline void __skb_queue_before(struct sk_buff_head *list, -+ struct sk_buff *next, -+ struct sk_buff *newsk) -+{ -+ __skb_insert(newsk, next->prev, next, list); -+} -+static inline void skb_queue_tail(struct sk_buff_head *list, -+ struct sk_buff *newsk) -+{ -+ mtx_lock(&list->lock); -+ __skb_queue_before(list, (struct sk_buff *)list, newsk); -+ mtx_unlock(&list->lock); -+} -+static inline struct sk_buff *skb_peek(struct sk_buff_head *list_) -+{ -+ struct sk_buff *list = ((struct sk_buff *)list_)->next; -+ if (list == (struct sk_buff *)list_) -+ list = NULL; -+ return list; -+} -+static inline void __skb_unlink(struct sk_buff *skb, struct sk_buff_head *list) -+{ -+ struct sk_buff *next, *prev; -+ -+ list->qlen--; -+ next = skb->next; -+ prev = skb->prev; -+ skb->next = skb->prev = NULL; -+ next->prev = prev; -+ prev->next = next; -+} -+ -+static inline struct sk_buff *skb_dequeue(struct sk_buff_head *list) -+{ -+ mtx_lock(&list->lock); -+ -+ struct sk_buff *skb = skb_peek(list); -+ if (skb) -+ __skb_unlink(skb, list); -+ -+ mtx_unlock(&list->lock); -+ -+ return skb; -+} -+static inline void skb_reserve(struct sk_buff *skb, int len) -+{ -+ skb->data += len; -+ skb->tail += len; -+} -+static inline void __skb_queue_head_init(struct sk_buff_head *list) -+{ -+ list->prev = list->next = (struct sk_buff *)list; -+ list->qlen = 0; -+} -+/* -+ * This function creates a split out lock class for each invocation; -+ * this is needed for now since a whole lot of users of the skb-queue -+ * infrastructure in drivers have different locking usage (in hardirq) -+ * than the networking core (in softirq only). In the long run either the -+ * network layer or drivers should need annotation to consolidate the -+ * main types of usage into 3 classes. -+ */ -+static inline void skb_queue_head_init(struct sk_buff_head *list) -+{ -+ _rtw_spinlock_init(&list->lock); -+ __skb_queue_head_init(list); -+} -+unsigned long copy_from_user(void *to, const void *from, unsigned long n); -+unsigned long copy_to_user(void *to, const void *from, unsigned long n); -+struct sk_buff * dev_alloc_skb(unsigned int size); -+struct sk_buff *skb_clone(const struct sk_buff *skb); -+void dev_kfree_skb_any(struct sk_buff *skb); -+#endif //Baron porting from linux, it's all temp solution, needs to check again -+ -+ -+#if 1 // kenny add Linux compatibility code for Linux USB driver -+#include -+ -+#define __init // __attribute ((constructor)) -+#define __exit // __attribute ((destructor)) -+ -+/* -+ * Definitions for module_init and module_exit macros. -+ * -+ * These macros will use the SYSINIT framework to call a specified -+ * function (with no arguments) on module loading or unloading. -+ * -+ */ -+ -+void module_init_exit_wrapper(void *arg); -+ -+#define module_init(initfn) \ -+ SYSINIT(mod_init_ ## initfn, \ -+ SI_SUB_KLD, SI_ORDER_FIRST, \ -+ module_init_exit_wrapper, initfn) -+ -+#define module_exit(exitfn) \ -+ SYSUNINIT(mod_exit_ ## exitfn, \ -+ SI_SUB_KLD, SI_ORDER_ANY, \ -+ module_init_exit_wrapper, exitfn) -+ -+/* -+ * The usb_register and usb_deregister functions are used to register -+ * usb drivers with the usb subsystem. -+ */ -+int usb_register(struct usb_driver *driver); -+int usb_deregister(struct usb_driver *driver); -+ -+/* -+ * usb_get_dev and usb_put_dev - increment/decrement the reference count -+ * of the usb device structure. -+ * -+ * Original body of usb_get_dev: -+ * -+ * if (dev) -+ * get_device(&dev->dev); -+ * return dev; -+ * -+ * Reference counts are not currently used in this compatibility -+ * layer. So these functions will do nothing. -+ */ -+static inline struct usb_device * -+usb_get_dev(struct usb_device *dev) -+{ -+ return dev; -+} -+ -+static inline void -+usb_put_dev(struct usb_device *dev) -+{ -+ return; -+} -+ -+ -+// rtw_usb_compat_linux -+int rtw_usb_submit_urb(struct urb *urb, uint16_t mem_flags); -+int rtw_usb_unlink_urb(struct urb *urb); -+int rtw_usb_clear_halt(struct usb_device *dev, struct usb_host_endpoint *uhe); -+int rtw_usb_control_msg(struct usb_device *dev, struct usb_host_endpoint *uhe, -+ uint8_t request, uint8_t requesttype, -+ uint16_t value, uint16_t index, void *data, -+ uint16_t size, usb_timeout_t timeout); -+int rtw_usb_set_interface(struct usb_device *dev, uint8_t iface_no, uint8_t alt_index); -+int rtw_usb_setup_endpoint(struct usb_device *dev, -+ struct usb_host_endpoint *uhe, usb_size_t bufsize); -+struct urb *rtw_usb_alloc_urb(uint16_t iso_packets, uint16_t mem_flags); -+struct usb_host_endpoint *rtw_usb_find_host_endpoint(struct usb_device *dev, uint8_t type, uint8_t ep); -+struct usb_host_interface *rtw_usb_altnum_to_altsetting(const struct usb_interface *intf, uint8_t alt_index); -+struct usb_interface *rtw_usb_ifnum_to_if(struct usb_device *dev, uint8_t iface_no); -+void *rtw_usbd_get_intfdata(struct usb_interface *intf); -+void rtw_usb_linux_register(void *arg); -+void rtw_usb_linux_deregister(void *arg); -+void rtw_usb_linux_free_device(struct usb_device *dev); -+void rtw_usb_free_urb(struct urb *urb); -+void rtw_usb_init_urb(struct urb *urb); -+void rtw_usb_kill_urb(struct urb *urb); -+void rtw_usb_set_intfdata(struct usb_interface *intf, void *data); -+void rtw_usb_fill_bulk_urb(struct urb *urb, struct usb_device *udev, -+ struct usb_host_endpoint *uhe, void *buf, -+ int length, usb_complete_t callback, void *arg); -+int rtw_usb_bulk_msg(struct usb_device *udev, struct usb_host_endpoint *uhe, -+ void *data, int len, uint16_t *pactlen, usb_timeout_t timeout); -+void *usb_get_intfdata(struct usb_interface *intf); -+int usb_linux_init_endpoints(struct usb_device *udev); -+ -+ -+ -+typedef struct urb * PURB; -+ -+typedef unsigned gfp_t; -+#define __GFP_WAIT ((gfp_t)0x10u) /* Can wait and reschedule? */ -+#define __GFP_HIGH ((gfp_t)0x20u) /* Should access emergency pools? */ -+#define __GFP_IO ((gfp_t)0x40u) /* Can start physical IO? */ -+#define __GFP_FS ((gfp_t)0x80u) /* Can call down to low-level FS? */ -+#define __GFP_COLD ((gfp_t)0x100u) /* Cache-cold page required */ -+#define __GFP_NOWARN ((gfp_t)0x200u) /* Suppress page allocation failure warning */ -+#define __GFP_REPEAT ((gfp_t)0x400u) /* Retry the allocation. Might fail */ -+#define __GFP_NOFAIL ((gfp_t)0x800u) /* Retry for ever. Cannot fail */ -+#define __GFP_NORETRY ((gfp_t)0x1000u)/* Do not retry. Might fail */ -+#define __GFP_NO_GROW ((gfp_t)0x2000u)/* Slab internal usage */ -+#define __GFP_COMP ((gfp_t)0x4000u)/* Add compound page metadata */ -+#define __GFP_ZERO ((gfp_t)0x8000u)/* Return zeroed page on success */ -+#define __GFP_NOMEMALLOC ((gfp_t)0x10000u) /* Don't use emergency reserves */ -+#define __GFP_HARDWALL ((gfp_t)0x20000u) /* Enforce hardwall cpuset memory allocs */ -+ -+/* This equals 0, but use constants in case they ever change */ -+#define GFP_NOWAIT (GFP_ATOMIC & ~__GFP_HIGH) -+/* GFP_ATOMIC means both !wait (__GFP_WAIT not set) and use emergency pool */ -+#define GFP_ATOMIC (__GFP_HIGH) -+#define GFP_NOIO (__GFP_WAIT) -+#define GFP_NOFS (__GFP_WAIT | __GFP_IO) -+#define GFP_KERNEL (__GFP_WAIT | __GFP_IO | __GFP_FS) -+#define GFP_USER (__GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL) -+#define GFP_HIGHUSER (__GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL | \ -+ __GFP_HIGHMEM) -+ -+ -+#endif // kenny add Linux compatibility code for Linux USB -+ -+__inline static _list *get_next(_list *list) -+{ -+ return list->next; -+} -+ -+__inline static _list *get_list_head(_queue *queue) -+{ -+ return (&(queue->queue)); -+} -+ -+ -+#define LIST_CONTAINOR(ptr, type, member) \ -+ ((type *)((char *)(ptr)-(SIZE_T)(&((type *)0)->member))) -+ -+ -+__inline static void _enter_critical(_lock *plock, _irqL *pirqL) -+{ -+ spin_lock_irqsave(plock, *pirqL); -+} -+ -+__inline static void _exit_critical(_lock *plock, _irqL *pirqL) -+{ -+ spin_unlock_irqrestore(plock, *pirqL); -+} -+ -+__inline static void _enter_critical_ex(_lock *plock, _irqL *pirqL) -+{ -+ spin_lock_irqsave(plock, *pirqL); -+} -+ -+__inline static void _exit_critical_ex(_lock *plock, _irqL *pirqL) -+{ -+ spin_unlock_irqrestore(plock, *pirqL); -+} -+ -+__inline static void _enter_critical_bh(_lock *plock, _irqL *pirqL) -+{ -+ spin_lock_bh(plock, *pirqL); -+} -+ -+__inline static void _exit_critical_bh(_lock *plock, _irqL *pirqL) -+{ -+ spin_unlock_bh(plock, *pirqL); -+} -+ -+__inline static void _enter_critical_mutex(_mutex *pmutex, _irqL *pirqL) -+{ -+ -+ mtx_lock(pmutex); -+ -+} -+ -+ -+__inline static void _exit_critical_mutex(_mutex *pmutex, _irqL *pirqL) -+{ -+ -+ mtx_unlock(pmutex); -+ -+} -+static inline void __list_del(struct list_head * prev, struct list_head * next) -+{ -+ next->prev = prev; -+ prev->next = next; -+} -+static inline void INIT_LIST_HEAD(struct list_head *list) -+{ -+ list->next = list; -+ list->prev = list; -+} -+__inline static void rtw_list_delete(_list *plist) -+{ -+ __list_del(plist->prev, plist->next); -+ INIT_LIST_HEAD(plist); -+} -+ -+static inline void timer_hdl(void *ctx) -+{ -+ _timer *timer = (_timer *)ctx; -+ -+ rtw_mtx_lock(NULL); -+ if (callout_pending(&timer->callout)) { -+ /* callout was reset */ -+ rtw_mtx_unlock(NULL); -+ return; -+ } -+ -+ if (!callout_active(&timer->callout)) { -+ /* callout was stopped */ -+ rtw_mtx_unlock(NULL); -+ return; -+ } -+ -+ callout_deactivate(&timer->callout); -+ -+ timer->function(timer->arg); -+ -+ rtw_mtx_unlock(NULL); -+} -+ -+static inline void _init_timer(_timer *ptimer, _nic_hdl padapter, void *pfunc, void *cntx) -+{ -+ ptimer->function = pfunc; -+ ptimer->arg = cntx; -+ callout_init(&ptimer->callout, CALLOUT_MPSAFE); -+} -+ -+__inline static void _set_timer(_timer *ptimer,u32 delay_time) -+{ -+ if (ptimer->function && ptimer->arg) { -+ rtw_mtx_lock(NULL); -+ callout_reset(&ptimer->callout, delay_time, timer_hdl, ptimer); -+ rtw_mtx_unlock(NULL); -+ } -+} -+ -+__inline static void _cancel_timer(_timer *ptimer,u8 *bcancelled) -+{ -+ rtw_mtx_lock(NULL); -+ callout_drain(&ptimer->callout); -+ rtw_mtx_unlock(NULL); -+ *bcancelled = 1; /* assume an pending timer to be canceled */ -+} -+ -+__inline static void _init_workitem(_workitem *pwork, void *pfunc, PVOID cntx) -+{ -+ printf("%s Not implement yet! \n",__FUNCTION__); -+} -+ -+__inline static void _set_workitem(_workitem *pwork) -+{ -+ printf("%s Not implement yet! \n",__FUNCTION__); -+// schedule_work(pwork); -+} -+ -+// -+// Global Mutex: can only be used at PASSIVE level. -+// -+ -+#define ACQUIRE_GLOBAL_MUTEX(_MutexCounter) \ -+{ \ -+} -+ -+#define RELEASE_GLOBAL_MUTEX(_MutexCounter) \ -+{ \ -+} -+ -+#define ATOMIC_INIT(i) { (i) } -+ -+static __inline void thread_enter(char *name); -+ -+//Atomic integer operations -+typedef uint32_t ATOMIC_T ; -+ -+#define rtw_netdev_priv(netdev) (((struct ifnet *)netdev)->if_softc) -+ -+#define rtw_free_netdev(netdev) if_free((netdev)) -+ -+#define NDEV_FMT "%s" -+#define NDEV_ARG(ndev) "" -+#define ADPT_FMT "%s" -+#define ADPT_ARG(adapter) "" -+#define FUNC_NDEV_FMT "%s" -+#define FUNC_NDEV_ARG(ndev) __func__ -+#define FUNC_ADPT_FMT "%s" -+#define FUNC_ADPT_ARG(adapter) __func__ -+ -+#define STRUCT_PACKED -+ -+#endif -+ -diff --git linux-5.8/3rdparty/rtl8812au/include/osdep_service_ce.h linux-5.8/3rdparty/rtl8812au/include/osdep_service_ce.h -new file mode 100644 -index 000000000..a406d62e7 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/osdep_service_ce.h -@@ -0,0 +1,200 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+ -+#ifndef __OSDEP_CE_SERVICE_H_ -+#define __OSDEP_CE_SERVICE_H_ -+ -+ -+#include -+#include -+ -+#ifdef CONFIG_SDIO_HCI -+#include "SDCardDDK.h" -+#endif -+ -+#ifdef CONFIG_USB_HCI -+#include -+#endif -+ -+typedef HANDLE _sema; -+typedef LIST_ENTRY _list; -+typedef NDIS_STATUS _OS_STATUS; -+ -+typedef NDIS_SPIN_LOCK _lock; -+ -+typedef HANDLE _rwlock; //Mutex -+ -+typedef u32 _irqL; -+ -+typedef NDIS_HANDLE _nic_hdl; -+ -+struct rtw_timer_list { -+ NDIS_MINIPORT_TIMER ndis_timer; -+ void (*function)(void *); -+ void *arg; -+}; -+ -+struct __queue { -+ LIST_ENTRY queue; -+ _lock lock; -+}; -+ -+typedef NDIS_PACKET _pkt; -+typedef NDIS_BUFFER _buffer; -+typedef struct __queue _queue; -+ -+typedef HANDLE _thread_hdl_; -+typedef DWORD thread_return; -+typedef void* thread_context; -+typedef NDIS_WORK_ITEM _workitem; -+ -+ -+ -+#define SEMA_UPBND (0x7FFFFFFF) //8192 -+ -+__inline static _list *get_prev(_list *list) -+{ -+ return list->Blink; -+} -+ -+__inline static _list *get_next(_list *list) -+{ -+ return list->Flink; -+} -+ -+__inline static _list *get_list_head(_queue *queue) -+{ -+ return (&(queue->queue)); -+} -+ -+#define LIST_CONTAINOR(ptr, type, member) CONTAINING_RECORD(ptr, type, member) -+ -+__inline static void _enter_critical(_lock *plock, _irqL *pirqL) -+{ -+ NdisAcquireSpinLock(plock); -+} -+ -+__inline static void _exit_critical(_lock *plock, _irqL *pirqL) -+{ -+ NdisReleaseSpinLock(plock); -+} -+ -+__inline static _enter_critical_ex(_lock *plock, _irqL *pirqL) -+{ -+ NdisDprAcquireSpinLock(plock); -+} -+ -+__inline static _exit_critical_ex(_lock *plock, _irqL *pirqL) -+{ -+ NdisDprReleaseSpinLock(plock); -+} -+ -+ -+__inline static void _enter_hwio_critical(_rwlock *prwlock, _irqL *pirqL) -+{ -+ WaitForSingleObject(*prwlock, INFINITE ); -+ -+} -+ -+__inline static void _exit_hwio_critical(_rwlock *prwlock, _irqL *pirqL) -+{ -+ ReleaseMutex(*prwlock); -+} -+ -+__inline static void rtw_list_delete(_list *plist) -+{ -+ RemoveEntryList(plist); -+ InitializeListHead(plist); -+} -+ -+static inline void timer_hdl( -+ IN PVOID SystemSpecific1, -+ IN PVOID FunctionContext, -+ IN PVOID SystemSpecific2, -+ IN PVOID SystemSpecific3) -+{ -+ _timer *timer = (_timer *)FunctionContext; -+ -+ timer->function(timer->arg); -+} -+ -+static inline void _init_timer(_timer *ptimer, _nic_hdl nic_hdl, void *pfunc, void *cntx) -+{ -+ ptimer->function = pfunc; -+ ptimer->arg = cntx; -+ NdisMInitializeTimer(&ptimer->ndis_timer, nic_hdl, timer_hdl, ptimer); -+} -+ -+static inline void _set_timer(_timer *ptimer, u32 delay_time) -+{ -+ NdisMSetTimer(ptimer, delay_time); -+} -+ -+static inline void _cancel_timer(_timer *ptimer, u8 *bcancelled) -+{ -+ NdisMCancelTimer(ptimer, bcancelled); -+} -+ -+__inline static void _init_workitem(_workitem *pwork, void *pfunc, PVOID cntx) -+{ -+ -+ NdisInitializeWorkItem(pwork, pfunc, cntx); -+} -+ -+__inline static void _set_workitem(_workitem *pwork) -+{ -+ NdisScheduleWorkItem(pwork); -+} -+ -+#define ATOMIC_INIT(i) { (i) } -+ -+// -+// Global Mutex: can only be used at PASSIVE level. -+// -+ -+#define ACQUIRE_GLOBAL_MUTEX(_MutexCounter) \ -+{ \ -+ while (NdisInterlockedIncrement((PULONG)&(_MutexCounter)) != 1)\ -+ { \ -+ NdisInterlockedDecrement((PULONG)&(_MutexCounter)); \ -+ NdisMSleep(10000); \ -+ } \ -+} -+ -+#define RELEASE_GLOBAL_MUTEX(_MutexCounter) \ -+{ \ -+ NdisInterlockedDecrement((PULONG)&(_MutexCounter)); \ -+} -+ -+// limitation of path length -+#define PATH_LENGTH_MAX MAX_PATH -+ -+//Atomic integer operations -+#define ATOMIC_T LONG -+ -+#define NDEV_FMT "%s" -+#define NDEV_ARG(ndev) "" -+#define ADPT_FMT "%s" -+#define ADPT_ARG(adapter) "" -+#define FUNC_NDEV_FMT "%s" -+#define FUNC_NDEV_ARG(ndev) __func__ -+#define FUNC_ADPT_FMT "%s" -+#define FUNC_ADPT_ARG(adapter) __func__ -+ -+#define STRUCT_PACKED -+ -+ -+#endif -+ -diff --git linux-5.8/3rdparty/rtl8812au/include/osdep_service_linux.h linux-5.8/3rdparty/rtl8812au/include/osdep_service_linux.h -new file mode 100644 -index 000000000..684d685d0 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/osdep_service_linux.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/osdep_service_linux.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/osdep_service_linux.h +--- linux-5.11.4/3rdparty/rtl8812au/include/osdep_service_linux.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/osdep_service_linux.h 2021-03-07 18:16:17.087957613 +0200 @@ -0,0 +1,543 @@ +/****************************************************************************** + * @@ -391009,11 +387517,9 @@ index 000000000..684d685d0 + + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/osdep_service_xp.h linux-5.8/3rdparty/rtl8812au/include/osdep_service_xp.h -new file mode 100644 -index 000000000..71dc1cd01 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/osdep_service_xp.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/osdep_service_xp.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/osdep_service_xp.h +--- linux-5.11.4/3rdparty/rtl8812au/include/osdep_service_xp.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/osdep_service_xp.h 2021-03-07 18:16:17.087957613 +0200 @@ -0,0 +1,210 @@ +/****************************************************************************** + * @@ -391225,11 +387731,9 @@ index 000000000..71dc1cd01 + +#endif + -diff --git linux-5.8/3rdparty/rtl8812au/include/pci_hal.h linux-5.8/3rdparty/rtl8812au/include/pci_hal.h -new file mode 100644 -index 000000000..15e4a796f ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/pci_hal.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/pci_hal.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/pci_hal.h +--- linux-5.11.4/3rdparty/rtl8812au/include/pci_hal.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/pci_hal.h 2021-03-07 18:16:17.087957613 +0200 @@ -0,0 +1,52 @@ +/****************************************************************************** + * @@ -391283,11 +387787,9 @@ index 000000000..15e4a796f +u8 rtw_set_hal_ops(_adapter *padapter); + +#endif /* __PCIE_HAL_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/pci_ops.h linux-5.8/3rdparty/rtl8812au/include/pci_ops.h -new file mode 100644 -index 000000000..6e4e0fabb ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/pci_ops.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/pci_ops.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/pci_ops.h +--- linux-5.11.4/3rdparty/rtl8812au/include/pci_ops.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/pci_ops.h 2021-03-07 18:16:17.087957613 +0200 @@ -0,0 +1,109 @@ +/****************************************************************************** + * @@ -391398,11 +387900,9 @@ index 000000000..6e4e0fabb +#endif + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/pci_osintf.h linux-5.8/3rdparty/rtl8812au/include/pci_osintf.h -new file mode 100644 -index 000000000..c6a0fddf6 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/pci_osintf.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/pci_osintf.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/pci_osintf.h +--- linux-5.11.4/3rdparty/rtl8812au/include/pci_osintf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/pci_osintf.h 2021-03-07 18:16:17.087957613 +0200 @@ -0,0 +1,50 @@ +/****************************************************************************** + * @@ -391454,11 +387954,9 @@ index 000000000..c6a0fddf6 +#endif + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/recv_osdep.h linux-5.8/3rdparty/rtl8812au/include/recv_osdep.h -new file mode 100644 -index 000000000..8c569b6dd ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/recv_osdep.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/recv_osdep.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/recv_osdep.h +--- linux-5.11.4/3rdparty/rtl8812au/include/recv_osdep.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/recv_osdep.h 2021-03-07 18:16:17.087957613 +0200 @@ -0,0 +1,67 @@ +/****************************************************************************** + * @@ -391527,11 +388025,9 @@ index 000000000..8c569b6dd +#endif /* PLATFORM_LINUX */ + +#endif /* */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtl8812a_cmd.h linux-5.8/3rdparty/rtl8812au/include/rtl8812a_cmd.h -new file mode 100644 -index 000000000..5b55fdf59 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtl8812a_cmd.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8812a_cmd.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8812a_cmd.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtl8812a_cmd.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8812a_cmd.h 2021-03-07 18:16:17.088957660 +0200 @@ -0,0 +1,158 @@ +/****************************************************************************** + * @@ -391691,11 +388187,9 @@ index 000000000..5b55fdf59 +s32 c2h_handler_8812a(_adapter *adapter, u8 id, u8 seq, u8 plen, u8 *payload); + +#endif/* __RTL8812A_CMD_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtl8812a_dm.h linux-5.8/3rdparty/rtl8812au/include/rtl8812a_dm.h -new file mode 100644 -index 000000000..584f6d342 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtl8812a_dm.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8812a_dm.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8812a_dm.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtl8812a_dm.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8812a_dm.h 2021-03-07 18:16:17.088957660 +0200 @@ -0,0 +1,27 @@ +/****************************************************************************** + * @@ -391724,11 +388218,9 @@ index 000000000..584f6d342 +/* void rtl8192c_dm_RF_Saving(IN PADAPTER pAdapter, IN u8 bForceInNormal); */ + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/rtl8812a_hal.h linux-5.8/3rdparty/rtl8812au/include/rtl8812a_hal.h -new file mode 100644 -index 000000000..1ecfb72e4 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtl8812a_hal.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8812a_hal.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8812a_hal.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtl8812a_hal.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8812a_hal.h 2021-03-07 18:16:17.088957660 +0200 @@ -0,0 +1,369 @@ +/****************************************************************************** + * @@ -392099,11 +388591,9 @@ index 000000000..1ecfb72e4 +); + +#endif /* __RTL8188E_HAL_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtl8812a_led.h linux-5.8/3rdparty/rtl8812au/include/rtl8812a_led.h -new file mode 100644 -index 000000000..30c676e52 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtl8812a_led.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8812a_led.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8812a_led.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtl8812a_led.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8812a_led.h 2021-03-07 18:16:17.088957660 +0200 @@ -0,0 +1,41 @@ +/****************************************************************************** + * @@ -392146,11 +388636,9 @@ index 000000000..30c676e52 +#endif + +#endif /*__RTL8812A_LED_H__*/ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtl8812a_recv.h linux-5.8/3rdparty/rtl8812au/include/rtl8812a_recv.h -new file mode 100644 -index 000000000..bf1d4b651 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtl8812a_recv.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8812a_recv.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8812a_recv.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtl8812a_recv.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8812a_recv.h 2021-03-07 18:16:17.088957660 +0200 @@ -0,0 +1,153 @@ +/****************************************************************************** + * @@ -392305,11 +388793,9 @@ index 000000000..bf1d4b651 +void rtl8812_query_rx_desc_status(union recv_frame *precvframe, u8 *pdesc); + +#endif /* __RTL8812A_RECV_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtl8812a_rf.h linux-5.8/3rdparty/rtl8812au/include/rtl8812a_rf.h -new file mode 100644 -index 000000000..9a7b60e61 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtl8812a_rf.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8812a_rf.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8812a_rf.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtl8812a_rf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8812a_rf.h 2021-03-07 18:16:17.088957660 +0200 @@ -0,0 +1,28 @@ +/****************************************************************************** + * @@ -392339,11 +388825,9 @@ index 000000000..9a7b60e61 + IN PADAPTER Adapter); + +#endif/* __RTL8188E_RF_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtl8812a_spec.h linux-5.8/3rdparty/rtl8812au/include/rtl8812a_spec.h -new file mode 100644 -index 000000000..37ba24722 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtl8812a_spec.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8812a_spec.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8812a_spec.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtl8812a_spec.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8812a_spec.h 2021-03-07 18:16:17.088957660 +0200 @@ -0,0 +1,263 @@ +/****************************************************************************** + * @@ -392608,11 +389092,9 @@ index 000000000..37ba24722 +#ifdef CONFIG_RTL8821A +#include "rtl8821a_spec.h" +#endif /* CONFIG_RTL8821A */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtl8812a_sreset.h linux-5.8/3rdparty/rtl8812au/include/rtl8812a_sreset.h -new file mode 100644 -index 000000000..13cbf5f25 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtl8812a_sreset.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8812a_sreset.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8812a_sreset.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtl8812a_sreset.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8812a_sreset.h 2021-03-07 18:16:17.088957660 +0200 @@ -0,0 +1,24 @@ +/****************************************************************************** + * @@ -392638,11 +389120,9 @@ index 000000000..13cbf5f25 +extern void rtl8812_sreset_linked_status_check(_adapter *padapter); +#endif +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/rtl8812a_xmit.h linux-5.8/3rdparty/rtl8812au/include/rtl8812a_xmit.h -new file mode 100644 -index 000000000..6105a8e41 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtl8812a_xmit.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8812a_xmit.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8812a_xmit.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtl8812a_xmit.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8812a_xmit.h 2021-03-07 18:16:17.088957660 +0200 @@ -0,0 +1,367 @@ +/****************************************************************************** + * @@ -393011,11 +389491,9 @@ index 000000000..6105a8e41 +#ifdef CONFIG_RTL8821A +#include "rtl8821a_xmit.h" +#endif /* CONFIG_RTL8821A */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtl8814a_cmd.h linux-5.8/3rdparty/rtl8812au/include/rtl8814a_cmd.h -new file mode 100644 -index 000000000..1c3e48bad ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtl8814a_cmd.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8814a_cmd.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8814a_cmd.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtl8814a_cmd.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8814a_cmd.h 2021-03-07 18:16:17.088957660 +0200 @@ -0,0 +1,162 @@ +/****************************************************************************** + * @@ -393179,11 +389657,9 @@ index 000000000..1c3e48bad +#endif /* CONFIG_P2P */ + +#endif/* __RTL8814A_CMD_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtl8814a_dm.h linux-5.8/3rdparty/rtl8812au/include/rtl8814a_dm.h -new file mode 100644 -index 000000000..afbc8be25 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtl8814a_dm.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8814a_dm.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8814a_dm.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtl8814a_dm.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8814a_dm.h 2021-03-07 18:16:17.088957660 +0200 @@ -0,0 +1,23 @@ +/****************************************************************************** + * @@ -393208,11 +389684,9 @@ index 000000000..afbc8be25 +void rtl8814_HalDmWatchDog(IN PADAPTER Adapter); + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/rtl8814a_hal.h linux-5.8/3rdparty/rtl8812au/include/rtl8814a_hal.h -new file mode 100644 -index 000000000..9670d36f0 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtl8814a_hal.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8814a_hal.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8814a_hal.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtl8814a_hal.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8814a_hal.h 2021-03-07 18:16:17.088957660 +0200 @@ -0,0 +1,330 @@ +/****************************************************************************** + * @@ -393544,11 +390018,9 @@ index 000000000..9670d36f0 +#endif + +#endif /* __RTL8188E_HAL_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtl8814a_led.h linux-5.8/3rdparty/rtl8812au/include/rtl8814a_led.h -new file mode 100644 -index 000000000..cc457921e ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtl8814a_led.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8814a_led.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8814a_led.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtl8814a_led.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8814a_led.h 2021-03-07 18:16:17.088957660 +0200 @@ -0,0 +1,36 @@ +/****************************************************************************** + * @@ -393586,11 +390058,9 @@ index 000000000..cc457921e + +#endif /* __RTL8814A_LED_H__ */ +#endif /*CONFIG_RTW_SW_LED*/ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtl8814a_recv.h linux-5.8/3rdparty/rtl8812au/include/rtl8814a_recv.h -new file mode 100644 -index 000000000..c6792d8a5 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtl8814a_recv.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8814a_recv.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8814a_recv.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtl8814a_recv.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8814a_recv.h 2021-03-07 18:16:17.088957660 +0200 @@ -0,0 +1,186 @@ +/****************************************************************************** + * @@ -393778,11 +390248,9 @@ index 000000000..c6792d8a5 +void rtl8814_query_rx_desc_status(union recv_frame *precvframe, u8 *pdesc); + +#endif /* __RTL8814A_RECV_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtl8814a_rf.h linux-5.8/3rdparty/rtl8812au/include/rtl8814a_rf.h -new file mode 100644 -index 000000000..e374439ca ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtl8814a_rf.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8814a_rf.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8814a_rf.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtl8814a_rf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8814a_rf.h 2021-03-07 18:16:17.088957660 +0200 @@ -0,0 +1,28 @@ +/****************************************************************************** + * @@ -393812,11 +390280,9 @@ index 000000000..e374439ca + IN PADAPTER Adapter); + +#endif/* __RTL8188E_RF_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtl8814a_spec.h linux-5.8/3rdparty/rtl8812au/include/rtl8814a_spec.h -new file mode 100644 -index 000000000..fd5fb0403 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtl8814a_spec.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8814a_spec.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8814a_spec.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtl8814a_spec.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8814a_spec.h 2021-03-07 18:16:17.088957660 +0200 @@ -0,0 +1,656 @@ +/****************************************************************************** + * @@ -394474,11 +390940,9 @@ index 000000000..fd5fb0403 +#define PROTO_CAP_8814A (PROTO_CAP_11B | PROTO_CAP_11G | PROTO_CAP_11N | PROTO_CAP_11AC) + +#endif /* __RTL8814A_SPEC_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtl8814a_sreset.h linux-5.8/3rdparty/rtl8812au/include/rtl8814a_sreset.h -new file mode 100644 -index 000000000..f5770c65b ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtl8814a_sreset.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8814a_sreset.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8814a_sreset.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtl8814a_sreset.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8814a_sreset.h 2021-03-07 18:16:17.088957660 +0200 @@ -0,0 +1,24 @@ +/****************************************************************************** + * @@ -394504,11 +390968,9 @@ index 000000000..f5770c65b + extern void rtl8814_sreset_linked_status_check(_adapter *padapter); +#endif +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/rtl8814a_xmit.h linux-5.8/3rdparty/rtl8812au/include/rtl8814a_xmit.h -new file mode 100644 -index 000000000..e3b6311af ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtl8814a_xmit.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8814a_xmit.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8814a_xmit.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtl8814a_xmit.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8814a_xmit.h 2021-03-07 18:16:17.088957660 +0200 @@ -0,0 +1,311 @@ +/****************************************************************************** + * @@ -394821,11 +391283,9 @@ index 000000000..e3b6311af + + +#endif /* __RTL8814_XMIT_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtl8821a_spec.h linux-5.8/3rdparty/rtl8812au/include/rtl8821a_spec.h -new file mode 100644 -index 000000000..1379ffc3c ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtl8821a_spec.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8821a_spec.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8821a_spec.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtl8821a_spec.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8821a_spec.h 2021-03-07 18:16:17.089957707 +0200 @@ -0,0 +1,90 @@ +/****************************************************************************** + * @@ -394917,11 +391377,9 @@ index 000000000..1379ffc3c + * ************************************************************ */ + +#endif /* __RTL8821A_SPEC_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtl8821a_xmit.h linux-5.8/3rdparty/rtl8812au/include/rtl8821a_xmit.h -new file mode 100644 -index 000000000..5d973cdc7 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtl8821a_xmit.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8821a_xmit.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8821a_xmit.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtl8821a_xmit.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl8821a_xmit.h 2021-03-07 18:16:17.089957707 +0200 @@ -0,0 +1,173 @@ +/****************************************************************************** + * @@ -395096,11 +391554,9 @@ index 000000000..5d973cdc7 +#endif + +#endif /* __RTL8821_XMIT_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtl_autoconf.h linux-5.8/3rdparty/rtl8812au/include/rtl_autoconf.h -new file mode 100644 -index 000000000..6ce3de050 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtl_autoconf.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl_autoconf.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl_autoconf.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtl_autoconf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtl_autoconf.h 2021-03-07 18:16:17.089957707 +0200 @@ -0,0 +1,363 @@ +/****************************************************************************** + * @@ -395465,11 +391921,9 @@ index 000000000..6ce3de050 +#define DBG_RX_DFRAME_RAW_DATA +/*#define CONFIG_USE_EXTERNAL_POWER */ /* NOT USB2.0 power, so no 500mA power constraint, no limitation in Power by Rate*/ +/*#define DBG_FW_DEBUG_MSG_PKT*/ /* FW use this feature to tx debug broadcast pkt. This pkt include FW debug message*/ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_android.h linux-5.8/3rdparty/rtl8812au/include/rtw_android.h -new file mode 100644 -index 000000000..f9d6b4972 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_android.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_android.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_android.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_android.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_android.h 2021-03-07 18:16:17.089957707 +0200 @@ -0,0 +1,113 @@ +/****************************************************************************** + * @@ -395584,11 +392038,9 @@ index 000000000..f9d6b4972 + + +#endif /* __RTW_ANDROID_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_ap.h linux-5.8/3rdparty/rtl8812au/include/rtw_ap.h -new file mode 100644 -index 000000000..7ad94d685 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_ap.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_ap.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_ap.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_ap.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_ap.h 2021-03-07 18:16:17.089957707 +0200 @@ -0,0 +1,112 @@ +/****************************************************************************** + * @@ -395702,11 +392154,9 @@ index 000000000..7ad94d685 + +#endif /* end of CONFIG_AP_MODE */ +#endif /*__RTW_AP_H_*/ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_beamforming.h linux-5.8/3rdparty/rtl8812au/include/rtw_beamforming.h -new file mode 100644 -index 000000000..cca5bcc1f ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_beamforming.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_beamforming.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_beamforming.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_beamforming.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_beamforming.h 2021-03-07 18:16:17.089957707 +0200 @@ -0,0 +1,401 @@ +/****************************************************************************** + * @@ -396109,11 +392559,9 @@ index 000000000..cca5bcc1f +#endif /*#ifdef CONFIG_BEAMFORMING */ + +#endif /*__RTW_BEAMFORMING_H_*/ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_br_ext.h linux-5.8/3rdparty/rtl8812au/include/rtw_br_ext.h -new file mode 100644 -index 000000000..54ba75ea1 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_br_ext.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_br_ext.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_br_ext.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_br_ext.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_br_ext.h 2021-03-07 18:16:17.089957707 +0200 @@ -0,0 +1,69 @@ +/****************************************************************************** + * @@ -396184,305 +392632,9 @@ index 000000000..54ba75ea1 +void nat25_db_cleanup(_adapter *priv); + +#endif /* _RTW_BR_EXT_H_ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_bt_mp.h linux-5.8/3rdparty/rtl8812au/include/rtw_bt_mp.h -new file mode 100644 -index 000000000..a152d18e9 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_bt_mp.h -@@ -0,0 +1,288 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+ -+#ifndef __RTW_BT_MP_H -+#define __RTW_BT_MP_H -+ -+ -+#if (MP_DRIVER == 1) -+ -+#pragma pack(1) -+ -+/* definition for BT_UP_OP_BT_READY */ -+#define MP_BT_NOT_READY 0 -+#define MP_BT_READY 1 -+ -+/* definition for BT_UP_OP_BT_SET_MODE */ -+typedef enum _MP_BT_MODE { -+ MP_BT_MODE_RF_TXRX_TEST_MODE = 0, -+ MP_BT_MODE_BT20_DUT_TEST_MODE = 1, -+ MP_BT_MODE_BT40_DIRECT_TEST_MODE = 2, -+ MP_BT_MODE_CONNECT_TEST_MODE = 3, -+ MP_BT_MODE_MAX -+} MP_BT_MODE, *PMP_BT_MODE; -+ -+ -+/* definition for BT_UP_OP_BT_SET_TX_RX_PARAMETER */ -+typedef struct _BT_TXRX_PARAMETERS { -+ u1Byte txrxChannel; -+ u4Byte txrxTxPktCnt; -+ u1Byte txrxTxPktInterval; -+ u1Byte txrxPayloadType; -+ u1Byte txrxPktType; -+ u2Byte txrxPayloadLen; -+ u4Byte txrxPktHeader; -+ u1Byte txrxWhitenCoeff; -+ u1Byte txrxBdaddr[6]; -+ u1Byte txrxTxGainIndex; -+} BT_TXRX_PARAMETERS, *PBT_TXRX_PARAMETERS; -+ -+/* txrxPktType */ -+typedef enum _MP_BT_PKT_TYPE { -+ MP_BT_PKT_DH1 = 0, -+ MP_BT_PKT_DH3 = 1, -+ MP_BT_PKT_DH5 = 2, -+ MP_BT_PKT_2DH1 = 3, -+ MP_BT_PKT_2DH3 = 4, -+ MP_BT_PKT_2DH5 = 5, -+ MP_BT_PKT_3DH1 = 6, -+ MP_BT_PKT_3DH3 = 7, -+ MP_BT_PKT_3DH5 = 8, -+ MP_BT_PKT_LE = 9, -+ MP_BT_PKT_MAX -+} MP_BT_PKT_TYPE, *PMP_BT_PKT_TYPE; -+/* txrxPayloadType */ -+typedef enum _MP_BT_PAYLOAD_TYPE { -+ MP_BT_PAYLOAD_01010101 = 0, -+ MP_BT_PAYLOAD_ALL_1 = 1, -+ MP_BT_PAYLOAD_ALL_0 = 2, -+ MP_BT_PAYLOAD_11110000 = 3, -+ MP_BT_PAYLOAD_PRBS9 = 4, -+ MP_BT_PAYLOAD_MAX = 8, -+} MP_BT_PAYLOAD_TYPE, *PMP_BT_PAYLOAD_TYPE; -+ -+ -+/* definition for BT_UP_OP_BT_TEST_CTRL */ -+typedef enum _MP_BT_TEST_CTRL { -+ MP_BT_TEST_STOP_ALL_TESTS = 0, -+ MP_BT_TEST_START_RX_TEST = 1, -+ MP_BT_TEST_START_PACKET_TX_TEST = 2, -+ MP_BT_TEST_START_CONTINUOUS_TX_TEST = 3, -+ MP_BT_TEST_START_INQUIRY_SCAN_TEST = 4, -+ MP_BT_TEST_START_PAGE_SCAN_TEST = 5, -+ MP_BT_TEST_START_INQUIRY_PAGE_SCAN_TEST = 6, -+ MP_BT_TEST_START_LEGACY_CONNECT_TEST = 7, -+ MP_BT_TEST_START_LE_CONNECT_TEST_INITIATOR = 8, -+ MP_BT_TEST_START_LE_CONNECT_TEST_ADVERTISER = 9, -+ MP_BT_TEST_MAX -+} MP_BT_TEST_CTRL, *PMP_BT_TEST_CTRL; -+ -+ -+typedef enum _RTL_EXT_C2H_EVT { -+ EXT_C2H_WIFI_FW_ACTIVE_RSP = 0, -+ EXT_C2H_TRIG_BY_BT_FW = 1, -+ MAX_EXT_C2HEVENT -+} RTL_EXT_C2H_EVT; -+ -+/* OP codes definition between the user layer and driver */ -+typedef enum _BT_CTRL_OPCODE_UPPER { -+ BT_UP_OP_BT_READY = 0x00, -+ BT_UP_OP_BT_SET_MODE = 0x01, -+ BT_UP_OP_BT_SET_TX_RX_PARAMETER = 0x02, -+ BT_UP_OP_BT_SET_GENERAL = 0x03, -+ BT_UP_OP_BT_GET_GENERAL = 0x04, -+ BT_UP_OP_BT_TEST_CTRL = 0x05, -+ BT_UP_OP_TEST_BT = 0x06, -+ BT_UP_OP_MAX -+} BT_CTRL_OPCODE_UPPER, *PBT_CTRL_OPCODE_UPPER; -+ -+ -+typedef enum _BT_SET_GENERAL { -+ BT_GSET_REG = 0x00, -+ BT_GSET_RESET = 0x01, -+ BT_GSET_TARGET_BD_ADDR = 0x02, -+ BT_GSET_TX_PWR_FINETUNE = 0x03, -+ BT_SET_TRACKING_INTERVAL = 0x04, -+ BT_SET_THERMAL_METER = 0x05, -+ BT_ENABLE_CFO_TRACKING = 0x06, -+ BT_GSET_UPDATE_BT_PATCH = 0x07, -+ BT_GSET_MAX -+} BT_SET_GENERAL, *PBT_SET_GENERAL; -+ -+typedef enum _BT_GET_GENERAL { -+ BT_GGET_REG = 0x00, -+ BT_GGET_STATUS = 0x01, -+ BT_GGET_REPORT = 0x02, -+ BT_GGET_AFH_MAP = 0x03, -+ BT_GGET_AFH_STATUS = 0x04, -+ BT_GGET_MAX -+} BT_GET_GENERAL, *PBT_GET_GENERAL; -+ -+/* definition for BT_UP_OP_BT_SET_GENERAL */ -+typedef enum _BT_REG_TYPE { -+ BT_REG_RF = 0, -+ BT_REG_MODEM = 1, -+ BT_REG_BLUEWIZE = 2, -+ BT_REG_VENDOR = 3, -+ BT_REG_LE = 4, -+ BT_REG_MAX -+} BT_REG_TYPE, *PBT_REG_TYPE; -+ -+/* definition for BT_LO_OP_GET_AFH_MAP */ -+typedef enum _BT_AFH_MAP_TYPE { -+ BT_AFH_MAP_RESULT = 0, -+ BT_AFH_MAP_WIFI_PSD_ONLY = 1, -+ BT_AFH_MAP_WIFI_CH_BW_ONLY = 2, -+ BT_AFH_MAP_BT_PSD_ONLY = 3, -+ BT_AFH_MAP_HOST_CLASSIFICATION_ONLY = 4, -+ BT_AFH_MAP_MAX -+} BT_AFH_MAP_TYPE, *PBT_AFH_MAP_TYPE; -+ -+/* definition for BT_UP_OP_BT_GET_GENERAL */ -+typedef enum _BT_REPORT_TYPE { -+ BT_REPORT_RX_PACKET_CNT = 0, -+ BT_REPORT_RX_ERROR_BITS = 1, -+ BT_REPORT_RSSI = 2, -+ BT_REPORT_CFO_HDR_QUALITY = 3, -+ BT_REPORT_CONNECT_TARGET_BD_ADDR = 4, -+ BT_REPORT_MAX -+} BT_REPORT_TYPE, *PBT_REPORT_TYPE; -+ -+VOID -+MPTBT_Test( -+ IN PADAPTER Adapter, -+ IN u1Byte opCode, -+ IN u1Byte byte1, -+ IN u1Byte byte2, -+ IN u1Byte byte3 -+); -+ -+NDIS_STATUS -+MPTBT_SendOidBT( -+ IN PADAPTER pAdapter, -+ IN PVOID InformationBuffer, -+ IN ULONG InformationBufferLength, -+ OUT PULONG BytesRead, -+ OUT PULONG BytesNeeded -+); -+ -+VOID -+MPTBT_FwC2hBtMpCtrl( -+ PADAPTER Adapter, -+ pu1Byte tmpBuf, -+ u1Byte length -+); -+ -+void MPh2c_timeout_handle(void *FunctionContext); -+ -+VOID mptbt_BtControlProcess( -+ PADAPTER Adapter, -+ PVOID pInBuf -+); -+ -+#define BT_H2C_MAX_RETRY 1 -+#define BT_MAX_C2H_LEN 20 -+ -+typedef struct _BT_REQ_CMD { -+ UCHAR opCodeVer; -+ UCHAR OpCode; -+ USHORT paraLength; -+ UCHAR pParamStart[100]; -+} BT_REQ_CMD, *PBT_REQ_CMD; -+ -+typedef struct _BT_RSP_CMD { -+ USHORT status; -+ USHORT paraLength; -+ UCHAR pParamStart[100]; -+} BT_RSP_CMD, *PBT_RSP_CMD; -+ -+ -+typedef struct _BT_H2C { -+ u1Byte opCodeVer:4; -+ u1Byte reqNum:4; -+ u1Byte opCode; -+ u1Byte buf[100]; -+} BT_H2C, *PBT_H2C; -+ -+ -+ -+typedef struct _BT_EXT_C2H { -+ u1Byte extendId; -+ u1Byte statusCode:4; -+ u1Byte retLen:4; -+ u1Byte opCodeVer:4; -+ u1Byte reqNum:4; -+ u1Byte buf[100]; -+} BT_EXT_C2H, *PBT_EXT_C2H; -+ -+ -+typedef enum _BT_OPCODE_STATUS { -+ BT_OP_STATUS_SUCCESS = 0x00, /* Success */ -+ BT_OP_STATUS_VERSION_MISMATCH = 0x01, -+ BT_OP_STATUS_UNKNOWN_OPCODE = 0x02, -+ BT_OP_STATUS_ERROR_PARAMETER = 0x03, -+ BT_OP_STATUS_MAX -+} BT_OPCODE_STATUS, *PBT_OPCODE_STATUS; -+ -+ -+ -+/* OP codes definition between driver and bt fw */ -+typedef enum _BT_CTRL_OPCODE_LOWER { -+ BT_LO_OP_GET_BT_VERSION = 0x00, -+ BT_LO_OP_RESET = 0x01, -+ BT_LO_OP_TEST_CTRL = 0x02, -+ BT_LO_OP_SET_BT_MODE = 0x03, -+ BT_LO_OP_SET_CHNL_TX_GAIN = 0x04, -+ BT_LO_OP_SET_PKT_TYPE_LEN = 0x05, -+ BT_LO_OP_SET_PKT_CNT_L_PL_TYPE = 0x06, -+ BT_LO_OP_SET_PKT_CNT_H_PKT_INTV = 0x07, -+ BT_LO_OP_SET_PKT_HEADER = 0x08, -+ BT_LO_OP_SET_WHITENCOEFF = 0x09, -+ BT_LO_OP_SET_BD_ADDR_L = 0x0a, -+ BT_LO_OP_SET_BD_ADDR_H = 0x0b, -+ BT_LO_OP_WRITE_REG_ADDR = 0x0c, -+ BT_LO_OP_WRITE_REG_VALUE = 0x0d, -+ BT_LO_OP_GET_BT_STATUS = 0x0e, -+ BT_LO_OP_GET_BD_ADDR_L = 0x0f, -+ BT_LO_OP_GET_BD_ADDR_H = 0x10, -+ BT_LO_OP_READ_REG = 0x11, -+ BT_LO_OP_SET_TARGET_BD_ADDR_L = 0x12, -+ BT_LO_OP_SET_TARGET_BD_ADDR_H = 0x13, -+ BT_LO_OP_SET_TX_POWER_CALIBRATION = 0x14, -+ BT_LO_OP_GET_RX_PKT_CNT_L = 0x15, -+ BT_LO_OP_GET_RX_PKT_CNT_H = 0x16, -+ BT_LO_OP_GET_RX_ERROR_BITS_L = 0x17, -+ BT_LO_OP_GET_RX_ERROR_BITS_H = 0x18, -+ BT_LO_OP_GET_RSSI = 0x19, -+ BT_LO_OP_GET_CFO_HDR_QUALITY_L = 0x1a, -+ BT_LO_OP_GET_CFO_HDR_QUALITY_H = 0x1b, -+ BT_LO_OP_GET_TARGET_BD_ADDR_L = 0x1c, -+ BT_LO_OP_GET_TARGET_BD_ADDR_H = 0x1d, -+ BT_LO_OP_GET_AFH_MAP_L = 0x1e, -+ BT_LO_OP_GET_AFH_MAP_M = 0x1f, -+ BT_LO_OP_GET_AFH_MAP_H = 0x20, -+ BT_LO_OP_GET_AFH_STATUS = 0x21, -+ BT_LO_OP_SET_TRACKING_INTERVAL = 0x22, -+ BT_LO_OP_SET_THERMAL_METER = 0x23, -+ BT_LO_OP_ENABLE_CFO_TRACKING = 0x24, -+ BT_LO_OP_MAX -+} BT_CTRL_OPCODE_LOWER, *PBT_CTRL_OPCODE_LOWER; -+ -+ -+ -+ -+#endif /* #if(MP_DRIVER == 1) */ -+ -+#endif /* #ifndef __INC_MPT_BT_H */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_btcoex.h linux-5.8/3rdparty/rtl8812au/include/rtw_btcoex.h -new file mode 100644 -index 000000000..fd422489a ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_btcoex.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_btcoex.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_btcoex.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_btcoex.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_btcoex.h 2021-03-07 18:16:17.089957707 +0200 @@ -0,0 +1,455 @@ +/****************************************************************************** + * @@ -396939,11 +393091,9 @@ index 000000000..fd422489a + +void rtw_btcoex_set_ant_info(PADAPTER padapter); + -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_btcoex_wifionly.h linux-5.8/3rdparty/rtl8812au/include/rtw_btcoex_wifionly.h -new file mode 100644 -index 000000000..93087ebe0 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_btcoex_wifionly.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_btcoex_wifionly.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_btcoex_wifionly.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_btcoex_wifionly.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_btcoex_wifionly.h 2021-03-07 18:16:17.089957707 +0200 @@ -0,0 +1,24 @@ +/****************************************************************************** + * @@ -396969,11 +393119,301 @@ index 000000000..93087ebe0 +void rtw_btcoex_wifionly_initialize(PADAPTER padapter); +void rtw_btcoex_wifionly_AntInfoSetting(PADAPTER padapter); +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_byteorder.h linux-5.8/3rdparty/rtl8812au/include/rtw_byteorder.h -new file mode 100644 -index 000000000..5177310a9 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_byteorder.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_bt_mp.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_bt_mp.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_bt_mp.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_bt_mp.h 2021-03-07 18:16:17.089957707 +0200 +@@ -0,0 +1,288 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++ ++#ifndef __RTW_BT_MP_H ++#define __RTW_BT_MP_H ++ ++ ++#if (MP_DRIVER == 1) ++ ++#pragma pack(1) ++ ++/* definition for BT_UP_OP_BT_READY */ ++#define MP_BT_NOT_READY 0 ++#define MP_BT_READY 1 ++ ++/* definition for BT_UP_OP_BT_SET_MODE */ ++typedef enum _MP_BT_MODE { ++ MP_BT_MODE_RF_TXRX_TEST_MODE = 0, ++ MP_BT_MODE_BT20_DUT_TEST_MODE = 1, ++ MP_BT_MODE_BT40_DIRECT_TEST_MODE = 2, ++ MP_BT_MODE_CONNECT_TEST_MODE = 3, ++ MP_BT_MODE_MAX ++} MP_BT_MODE, *PMP_BT_MODE; ++ ++ ++/* definition for BT_UP_OP_BT_SET_TX_RX_PARAMETER */ ++typedef struct _BT_TXRX_PARAMETERS { ++ u1Byte txrxChannel; ++ u4Byte txrxTxPktCnt; ++ u1Byte txrxTxPktInterval; ++ u1Byte txrxPayloadType; ++ u1Byte txrxPktType; ++ u2Byte txrxPayloadLen; ++ u4Byte txrxPktHeader; ++ u1Byte txrxWhitenCoeff; ++ u1Byte txrxBdaddr[6]; ++ u1Byte txrxTxGainIndex; ++} BT_TXRX_PARAMETERS, *PBT_TXRX_PARAMETERS; ++ ++/* txrxPktType */ ++typedef enum _MP_BT_PKT_TYPE { ++ MP_BT_PKT_DH1 = 0, ++ MP_BT_PKT_DH3 = 1, ++ MP_BT_PKT_DH5 = 2, ++ MP_BT_PKT_2DH1 = 3, ++ MP_BT_PKT_2DH3 = 4, ++ MP_BT_PKT_2DH5 = 5, ++ MP_BT_PKT_3DH1 = 6, ++ MP_BT_PKT_3DH3 = 7, ++ MP_BT_PKT_3DH5 = 8, ++ MP_BT_PKT_LE = 9, ++ MP_BT_PKT_MAX ++} MP_BT_PKT_TYPE, *PMP_BT_PKT_TYPE; ++/* txrxPayloadType */ ++typedef enum _MP_BT_PAYLOAD_TYPE { ++ MP_BT_PAYLOAD_01010101 = 0, ++ MP_BT_PAYLOAD_ALL_1 = 1, ++ MP_BT_PAYLOAD_ALL_0 = 2, ++ MP_BT_PAYLOAD_11110000 = 3, ++ MP_BT_PAYLOAD_PRBS9 = 4, ++ MP_BT_PAYLOAD_MAX = 8, ++} MP_BT_PAYLOAD_TYPE, *PMP_BT_PAYLOAD_TYPE; ++ ++ ++/* definition for BT_UP_OP_BT_TEST_CTRL */ ++typedef enum _MP_BT_TEST_CTRL { ++ MP_BT_TEST_STOP_ALL_TESTS = 0, ++ MP_BT_TEST_START_RX_TEST = 1, ++ MP_BT_TEST_START_PACKET_TX_TEST = 2, ++ MP_BT_TEST_START_CONTINUOUS_TX_TEST = 3, ++ MP_BT_TEST_START_INQUIRY_SCAN_TEST = 4, ++ MP_BT_TEST_START_PAGE_SCAN_TEST = 5, ++ MP_BT_TEST_START_INQUIRY_PAGE_SCAN_TEST = 6, ++ MP_BT_TEST_START_LEGACY_CONNECT_TEST = 7, ++ MP_BT_TEST_START_LE_CONNECT_TEST_INITIATOR = 8, ++ MP_BT_TEST_START_LE_CONNECT_TEST_ADVERTISER = 9, ++ MP_BT_TEST_MAX ++} MP_BT_TEST_CTRL, *PMP_BT_TEST_CTRL; ++ ++ ++typedef enum _RTL_EXT_C2H_EVT { ++ EXT_C2H_WIFI_FW_ACTIVE_RSP = 0, ++ EXT_C2H_TRIG_BY_BT_FW = 1, ++ MAX_EXT_C2HEVENT ++} RTL_EXT_C2H_EVT; ++ ++/* OP codes definition between the user layer and driver */ ++typedef enum _BT_CTRL_OPCODE_UPPER { ++ BT_UP_OP_BT_READY = 0x00, ++ BT_UP_OP_BT_SET_MODE = 0x01, ++ BT_UP_OP_BT_SET_TX_RX_PARAMETER = 0x02, ++ BT_UP_OP_BT_SET_GENERAL = 0x03, ++ BT_UP_OP_BT_GET_GENERAL = 0x04, ++ BT_UP_OP_BT_TEST_CTRL = 0x05, ++ BT_UP_OP_TEST_BT = 0x06, ++ BT_UP_OP_MAX ++} BT_CTRL_OPCODE_UPPER, *PBT_CTRL_OPCODE_UPPER; ++ ++ ++typedef enum _BT_SET_GENERAL { ++ BT_GSET_REG = 0x00, ++ BT_GSET_RESET = 0x01, ++ BT_GSET_TARGET_BD_ADDR = 0x02, ++ BT_GSET_TX_PWR_FINETUNE = 0x03, ++ BT_SET_TRACKING_INTERVAL = 0x04, ++ BT_SET_THERMAL_METER = 0x05, ++ BT_ENABLE_CFO_TRACKING = 0x06, ++ BT_GSET_UPDATE_BT_PATCH = 0x07, ++ BT_GSET_MAX ++} BT_SET_GENERAL, *PBT_SET_GENERAL; ++ ++typedef enum _BT_GET_GENERAL { ++ BT_GGET_REG = 0x00, ++ BT_GGET_STATUS = 0x01, ++ BT_GGET_REPORT = 0x02, ++ BT_GGET_AFH_MAP = 0x03, ++ BT_GGET_AFH_STATUS = 0x04, ++ BT_GGET_MAX ++} BT_GET_GENERAL, *PBT_GET_GENERAL; ++ ++/* definition for BT_UP_OP_BT_SET_GENERAL */ ++typedef enum _BT_REG_TYPE { ++ BT_REG_RF = 0, ++ BT_REG_MODEM = 1, ++ BT_REG_BLUEWIZE = 2, ++ BT_REG_VENDOR = 3, ++ BT_REG_LE = 4, ++ BT_REG_MAX ++} BT_REG_TYPE, *PBT_REG_TYPE; ++ ++/* definition for BT_LO_OP_GET_AFH_MAP */ ++typedef enum _BT_AFH_MAP_TYPE { ++ BT_AFH_MAP_RESULT = 0, ++ BT_AFH_MAP_WIFI_PSD_ONLY = 1, ++ BT_AFH_MAP_WIFI_CH_BW_ONLY = 2, ++ BT_AFH_MAP_BT_PSD_ONLY = 3, ++ BT_AFH_MAP_HOST_CLASSIFICATION_ONLY = 4, ++ BT_AFH_MAP_MAX ++} BT_AFH_MAP_TYPE, *PBT_AFH_MAP_TYPE; ++ ++/* definition for BT_UP_OP_BT_GET_GENERAL */ ++typedef enum _BT_REPORT_TYPE { ++ BT_REPORT_RX_PACKET_CNT = 0, ++ BT_REPORT_RX_ERROR_BITS = 1, ++ BT_REPORT_RSSI = 2, ++ BT_REPORT_CFO_HDR_QUALITY = 3, ++ BT_REPORT_CONNECT_TARGET_BD_ADDR = 4, ++ BT_REPORT_MAX ++} BT_REPORT_TYPE, *PBT_REPORT_TYPE; ++ ++VOID ++MPTBT_Test( ++ IN PADAPTER Adapter, ++ IN u1Byte opCode, ++ IN u1Byte byte1, ++ IN u1Byte byte2, ++ IN u1Byte byte3 ++); ++ ++NDIS_STATUS ++MPTBT_SendOidBT( ++ IN PADAPTER pAdapter, ++ IN PVOID InformationBuffer, ++ IN ULONG InformationBufferLength, ++ OUT PULONG BytesRead, ++ OUT PULONG BytesNeeded ++); ++ ++VOID ++MPTBT_FwC2hBtMpCtrl( ++ PADAPTER Adapter, ++ pu1Byte tmpBuf, ++ u1Byte length ++); ++ ++void MPh2c_timeout_handle(void *FunctionContext); ++ ++VOID mptbt_BtControlProcess( ++ PADAPTER Adapter, ++ PVOID pInBuf ++); ++ ++#define BT_H2C_MAX_RETRY 1 ++#define BT_MAX_C2H_LEN 20 ++ ++typedef struct _BT_REQ_CMD { ++ UCHAR opCodeVer; ++ UCHAR OpCode; ++ USHORT paraLength; ++ UCHAR pParamStart[100]; ++} BT_REQ_CMD, *PBT_REQ_CMD; ++ ++typedef struct _BT_RSP_CMD { ++ USHORT status; ++ USHORT paraLength; ++ UCHAR pParamStart[100]; ++} BT_RSP_CMD, *PBT_RSP_CMD; ++ ++ ++typedef struct _BT_H2C { ++ u1Byte opCodeVer:4; ++ u1Byte reqNum:4; ++ u1Byte opCode; ++ u1Byte buf[100]; ++} BT_H2C, *PBT_H2C; ++ ++ ++ ++typedef struct _BT_EXT_C2H { ++ u1Byte extendId; ++ u1Byte statusCode:4; ++ u1Byte retLen:4; ++ u1Byte opCodeVer:4; ++ u1Byte reqNum:4; ++ u1Byte buf[100]; ++} BT_EXT_C2H, *PBT_EXT_C2H; ++ ++ ++typedef enum _BT_OPCODE_STATUS { ++ BT_OP_STATUS_SUCCESS = 0x00, /* Success */ ++ BT_OP_STATUS_VERSION_MISMATCH = 0x01, ++ BT_OP_STATUS_UNKNOWN_OPCODE = 0x02, ++ BT_OP_STATUS_ERROR_PARAMETER = 0x03, ++ BT_OP_STATUS_MAX ++} BT_OPCODE_STATUS, *PBT_OPCODE_STATUS; ++ ++ ++ ++/* OP codes definition between driver and bt fw */ ++typedef enum _BT_CTRL_OPCODE_LOWER { ++ BT_LO_OP_GET_BT_VERSION = 0x00, ++ BT_LO_OP_RESET = 0x01, ++ BT_LO_OP_TEST_CTRL = 0x02, ++ BT_LO_OP_SET_BT_MODE = 0x03, ++ BT_LO_OP_SET_CHNL_TX_GAIN = 0x04, ++ BT_LO_OP_SET_PKT_TYPE_LEN = 0x05, ++ BT_LO_OP_SET_PKT_CNT_L_PL_TYPE = 0x06, ++ BT_LO_OP_SET_PKT_CNT_H_PKT_INTV = 0x07, ++ BT_LO_OP_SET_PKT_HEADER = 0x08, ++ BT_LO_OP_SET_WHITENCOEFF = 0x09, ++ BT_LO_OP_SET_BD_ADDR_L = 0x0a, ++ BT_LO_OP_SET_BD_ADDR_H = 0x0b, ++ BT_LO_OP_WRITE_REG_ADDR = 0x0c, ++ BT_LO_OP_WRITE_REG_VALUE = 0x0d, ++ BT_LO_OP_GET_BT_STATUS = 0x0e, ++ BT_LO_OP_GET_BD_ADDR_L = 0x0f, ++ BT_LO_OP_GET_BD_ADDR_H = 0x10, ++ BT_LO_OP_READ_REG = 0x11, ++ BT_LO_OP_SET_TARGET_BD_ADDR_L = 0x12, ++ BT_LO_OP_SET_TARGET_BD_ADDR_H = 0x13, ++ BT_LO_OP_SET_TX_POWER_CALIBRATION = 0x14, ++ BT_LO_OP_GET_RX_PKT_CNT_L = 0x15, ++ BT_LO_OP_GET_RX_PKT_CNT_H = 0x16, ++ BT_LO_OP_GET_RX_ERROR_BITS_L = 0x17, ++ BT_LO_OP_GET_RX_ERROR_BITS_H = 0x18, ++ BT_LO_OP_GET_RSSI = 0x19, ++ BT_LO_OP_GET_CFO_HDR_QUALITY_L = 0x1a, ++ BT_LO_OP_GET_CFO_HDR_QUALITY_H = 0x1b, ++ BT_LO_OP_GET_TARGET_BD_ADDR_L = 0x1c, ++ BT_LO_OP_GET_TARGET_BD_ADDR_H = 0x1d, ++ BT_LO_OP_GET_AFH_MAP_L = 0x1e, ++ BT_LO_OP_GET_AFH_MAP_M = 0x1f, ++ BT_LO_OP_GET_AFH_MAP_H = 0x20, ++ BT_LO_OP_GET_AFH_STATUS = 0x21, ++ BT_LO_OP_SET_TRACKING_INTERVAL = 0x22, ++ BT_LO_OP_SET_THERMAL_METER = 0x23, ++ BT_LO_OP_ENABLE_CFO_TRACKING = 0x24, ++ BT_LO_OP_MAX ++} BT_CTRL_OPCODE_LOWER, *PBT_CTRL_OPCODE_LOWER; ++ ++ ++ ++ ++#endif /* #if(MP_DRIVER == 1) */ ++ ++#endif /* #ifndef __INC_MPT_BT_H */ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_byteorder.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_byteorder.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_byteorder.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_byteorder.h 2021-03-07 18:16:17.089957707 +0200 @@ -0,0 +1,45 @@ +/****************************************************************************** + * @@ -397020,11 +393460,9 @@ index 000000000..5177310a9 +#endif + +#endif /* _RTL871X_BYTEORDER_H_ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_cmd.h linux-5.8/3rdparty/rtl8812au/include/rtw_cmd.h -new file mode 100644 -index 000000000..4df67602f ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_cmd.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_cmd.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_cmd.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_cmd.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_cmd.h 2021-03-07 18:16:17.089957707 +0200 @@ -0,0 +1,1363 @@ +/****************************************************************************** + * @@ -398389,11 +394827,9 @@ index 000000000..4df67602f + (cmd)->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra) ? ((struct drvextra_cmd_parm *)(cmd)->parmbuf)->type : 0 + +#endif /* _CMD_H_ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_debug.h linux-5.8/3rdparty/rtl8812au/include/rtw_debug.h -new file mode 100644 -index 000000000..0d005c3c6 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_debug.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_debug.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_debug.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_debug.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_debug.h 2021-03-07 18:16:17.089957707 +0200 @@ -0,0 +1,653 @@ +/****************************************************************************** + * @@ -399048,11 +395484,9 @@ index 000000000..0d005c3c6 +#define _module_rtl8712_led_c_ BIT(31) + +#endif /* __RTW_DEBUG_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_eeprom.h linux-5.8/3rdparty/rtl8812au/include/rtw_eeprom.h -new file mode 100644 -index 000000000..62304d577 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_eeprom.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_eeprom.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_eeprom.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_eeprom.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_eeprom.h 2021-03-07 18:16:17.089957707 +0200 @@ -0,0 +1,116 @@ +/****************************************************************************** + * @@ -399170,11 +395604,9 @@ index 000000000..62304d577 +#endif /* PLATFORM_LINUX */ + +#endif /* __RTL871X_EEPROM_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_efuse.h linux-5.8/3rdparty/rtl8812au/include/rtw_efuse.h -new file mode 100644 -index 000000000..30527021c ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_efuse.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_efuse.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_efuse.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_efuse.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_efuse.h 2021-03-07 18:16:17.089957707 +0200 @@ -0,0 +1,255 @@ +/****************************************************************************** + * @@ -399431,11 +395863,9 @@ index 000000000..30527021c +#endif /* PLATFORM_LINUX */ + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_event.h linux-5.8/3rdparty/rtl8812au/include/rtw_event.h -new file mode 100644 -index 000000000..8e4d5d6f5 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_event.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_event.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_event.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_event.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_event.h 2021-03-07 18:16:17.089957707 +0200 @@ -0,0 +1,130 @@ +/****************************************************************************** + * @@ -399567,11 +395997,9 @@ index 000000000..8e4d5d6f5 + + +#endif /* _WLANEVENT_H_ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_ht.h linux-5.8/3rdparty/rtl8812au/include/rtw_ht.h -new file mode 100644 -index 000000000..8237bbe76 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_ht.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_ht.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_ht.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_ht.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_ht.h 2021-03-07 18:16:17.089957707 +0200 @@ -0,0 +1,217 @@ +/****************************************************************************** + * @@ -399790,11 +396218,511 @@ index 000000000..8237bbe76 +#define SET_HT_OP_ELE_PCO_PHASE(_pEleStart, _val) SET_BITS_TO_LE_1BYTE(((u8 *)(_pEleStart)) + 5, 3, 1, _val) + +#endif /* _RTL871X_HT_H_ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_io.h linux-5.8/3rdparty/rtl8812au/include/rtw_io.h -new file mode 100644 -index 000000000..cafb12df6 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_io.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_ioctl.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_ioctl.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_ioctl.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_ioctl.h 2021-03-07 18:16:17.090957755 +0200 +@@ -0,0 +1,319 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++#ifndef _RTW_IOCTL_H_ ++#define _RTW_IOCTL_H_ ++ ++#ifndef PLATFORM_WINDOWS ++/* 00 - Success ++* 11 - Error */ ++#define STATUS_SUCCESS (0x00000000L) ++#define STATUS_PENDING (0x00000103L) ++ ++#define STATUS_UNSUCCESSFUL (0xC0000001L) ++#define STATUS_INSUFFICIENT_RESOURCES (0xC000009AL) ++#define STATUS_NOT_SUPPORTED (0xC00000BBL) ++ ++#define NDIS_STATUS_SUCCESS ((NDIS_STATUS)STATUS_SUCCESS) ++#define NDIS_STATUS_PENDING ((NDIS_STATUS)STATUS_PENDING) ++#define NDIS_STATUS_NOT_RECOGNIZED ((NDIS_STATUS)0x00010001L) ++#define NDIS_STATUS_NOT_COPIED ((NDIS_STATUS)0x00010002L) ++#define NDIS_STATUS_NOT_ACCEPTED ((NDIS_STATUS)0x00010003L) ++#define NDIS_STATUS_CALL_ACTIVE ((NDIS_STATUS)0x00010007L) ++ ++#define NDIS_STATUS_FAILURE ((NDIS_STATUS)STATUS_UNSUCCESSFUL) ++#define NDIS_STATUS_RESOURCES ((NDIS_STATUS)STATUS_INSUFFICIENT_RESOURCES) ++#define NDIS_STATUS_CLOSING ((NDIS_STATUS)0xC0010002L) ++#define NDIS_STATUS_BAD_VERSION ((NDIS_STATUS)0xC0010004L) ++#define NDIS_STATUS_BAD_CHARACTERISTICS ((NDIS_STATUS)0xC0010005L) ++#define NDIS_STATUS_ADAPTER_NOT_FOUND ((NDIS_STATUS)0xC0010006L) ++#define NDIS_STATUS_OPEN_FAILED ((NDIS_STATUS)0xC0010007L) ++#define NDIS_STATUS_DEVICE_FAILED ((NDIS_STATUS)0xC0010008L) ++#define NDIS_STATUS_MULTICAST_FULL ((NDIS_STATUS)0xC0010009L) ++#define NDIS_STATUS_MULTICAST_EXISTS ((NDIS_STATUS)0xC001000AL) ++#define NDIS_STATUS_MULTICAST_NOT_FOUND ((NDIS_STATUS)0xC001000BL) ++#define NDIS_STATUS_REQUEST_ABORTED ((NDIS_STATUS)0xC001000CL) ++#define NDIS_STATUS_RESET_IN_PROGRESS ((NDIS_STATUS)0xC001000DL) ++#define NDIS_STATUS_CLOSING_INDICATING ((NDIS_STATUS)0xC001000EL) ++#define NDIS_STATUS_NOT_SUPPORTED ((NDIS_STATUS)STATUS_NOT_SUPPORTED) ++#define NDIS_STATUS_INVALID_PACKET ((NDIS_STATUS)0xC001000FL) ++#define NDIS_STATUS_OPEN_LIST_FULL ((NDIS_STATUS)0xC0010010L) ++#define NDIS_STATUS_ADAPTER_NOT_READY ((NDIS_STATUS)0xC0010011L) ++#define NDIS_STATUS_ADAPTER_NOT_OPEN ((NDIS_STATUS)0xC0010012L) ++#define NDIS_STATUS_NOT_INDICATING ((NDIS_STATUS)0xC0010013L) ++#define NDIS_STATUS_INVALID_LENGTH ((NDIS_STATUS)0xC0010014L) ++#define NDIS_STATUS_INVALID_DATA ((NDIS_STATUS)0xC0010015L) ++#define NDIS_STATUS_BUFFER_TOO_SHORT ((NDIS_STATUS)0xC0010016L) ++#define NDIS_STATUS_INVALID_OID ((NDIS_STATUS)0xC0010017L) ++#define NDIS_STATUS_ADAPTER_REMOVED ((NDIS_STATUS)0xC0010018L) ++#define NDIS_STATUS_UNSUPPORTED_MEDIA ((NDIS_STATUS)0xC0010019L) ++#define NDIS_STATUS_GROUP_ADDRESS_IN_USE ((NDIS_STATUS)0xC001001AL) ++#define NDIS_STATUS_FILE_NOT_FOUND ((NDIS_STATUS)0xC001001BL) ++#define NDIS_STATUS_ERROR_READING_FILE ((NDIS_STATUS)0xC001001CL) ++#define NDIS_STATUS_ALREADY_MAPPED ((NDIS_STATUS)0xC001001DL) ++#define NDIS_STATUS_RESOURCE_CONFLICT ((NDIS_STATUS)0xC001001EL) ++#define NDIS_STATUS_NO_CABLE ((NDIS_STATUS)0xC001001FL) ++ ++#define NDIS_STATUS_INVALID_SAP ((NDIS_STATUS)0xC0010020L) ++#define NDIS_STATUS_SAP_IN_USE ((NDIS_STATUS)0xC0010021L) ++#define NDIS_STATUS_INVALID_ADDRESS ((NDIS_STATUS)0xC0010022L) ++#define NDIS_STATUS_VC_NOT_ACTIVATED ((NDIS_STATUS)0xC0010023L) ++#define NDIS_STATUS_DEST_OUT_OF_ORDER ((NDIS_STATUS)0xC0010024L) /* cause 27 */ ++#define NDIS_STATUS_VC_NOT_AVAILABLE ((NDIS_STATUS)0xC0010025L) /* cause 35, 45 */ ++#define NDIS_STATUS_CELLRATE_NOT_AVAILABLE ((NDIS_STATUS)0xC0010026L) /* cause 37 */ ++#define NDIS_STATUS_INCOMPATABLE_QOS ((NDIS_STATUS)0xC0010027L) /* cause 49 */ ++#define NDIS_STATUS_AAL_PARAMS_UNSUPPORTED ((NDIS_STATUS)0xC0010028L) /* cause 93 */ ++#define NDIS_STATUS_NO_ROUTE_TO_DESTINATION ((NDIS_STATUS)0xC0010029L) /* cause 3 */ ++#endif /* #ifndef PLATFORM_WINDOWS */ ++ ++ ++#ifndef OID_802_11_CAPABILITY ++ #define OID_802_11_CAPABILITY 0x0d010122 ++#endif ++ ++#ifndef OID_802_11_PMKID ++ #define OID_802_11_PMKID 0x0d010123 ++#endif ++ ++ ++/* For DDK-defined OIDs */ ++#define OID_NDIS_SEG1 0x00010100 ++#define OID_NDIS_SEG2 0x00010200 ++#define OID_NDIS_SEG3 0x00020100 ++#define OID_NDIS_SEG4 0x01010100 ++#define OID_NDIS_SEG5 0x01020100 ++#define OID_NDIS_SEG6 0x01020200 ++#define OID_NDIS_SEG7 0xFD010100 ++#define OID_NDIS_SEG8 0x0D010100 ++#define OID_NDIS_SEG9 0x0D010200 ++#define OID_NDIS_SEG10 0x0D020200 ++ ++#define SZ_OID_NDIS_SEG1 23 ++#define SZ_OID_NDIS_SEG2 3 ++#define SZ_OID_NDIS_SEG3 6 ++#define SZ_OID_NDIS_SEG4 6 ++#define SZ_OID_NDIS_SEG5 4 ++#define SZ_OID_NDIS_SEG6 8 ++#define SZ_OID_NDIS_SEG7 7 ++#define SZ_OID_NDIS_SEG8 36 ++#define SZ_OID_NDIS_SEG9 24 ++#define SZ_OID_NDIS_SEG10 19 ++ ++/* For Realtek-defined OIDs */ ++#define OID_MP_SEG1 0xFF871100 ++#define OID_MP_SEG2 0xFF818000 ++ ++#define OID_MP_SEG3 0xFF818700 ++#define OID_MP_SEG4 0xFF011100 ++ ++enum oid_type { ++ QUERY_OID, ++ SET_OID ++}; ++ ++struct oid_funs_node { ++ unsigned int oid_start; /* the starting number for OID */ ++ unsigned int oid_end; /* the ending number for OID */ ++ struct oid_obj_priv *node_array; ++ unsigned int array_sz; /* the size of node_array */ ++ int query_counter; /* count the number of query hits for this segment */ ++ int set_counter; /* count the number of set hits for this segment */ ++}; ++ ++struct oid_par_priv { ++ void *adapter_context; ++ NDIS_OID oid; ++ void *information_buf; ++ u32 information_buf_len; ++ u32 *bytes_rw; ++ u32 *bytes_needed; ++ enum oid_type type_of_oid; ++ u32 dbg; ++}; ++ ++struct oid_obj_priv { ++ unsigned char dbg; /* 0: without OID debug message 1: with OID debug message */ ++ NDIS_STATUS(*oidfuns)(struct oid_par_priv *poid_par_priv); ++}; ++ ++#if (defined(CONFIG_MP_INCLUDED) && defined(_RTW_MP_IOCTL_C_)) || \ ++ (defined(PLATFORM_WINDOWS) && defined(_RTW_IOCTL_RTL_C_)) ++static NDIS_STATUS oid_null_function(struct oid_par_priv *poid_par_priv) ++{ ++ return NDIS_STATUS_SUCCESS; ++} ++#endif ++ ++#ifdef PLATFORM_WINDOWS ++ ++int TranslateNdisPsToRtPs(IN NDIS_802_11_POWER_MODE ndisPsMode); ++ ++/* OID Handler for Segment 1 */ ++NDIS_STATUS oid_gen_supported_list_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_gen_hardware_status_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_gen_media_supported_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_gen_media_in_use_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_gen_maximum_lookahead_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_gen_maximum_frame_size_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_gen_link_speed_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_gen_transmit_buffer_space_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_gen_receive_buffer_space_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_gen_transmit_block_size_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_gen_receive_block_size_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_gen_vendor_id_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_gen_vendor_description_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_gen_current_packet_filter_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_gen_current_lookahead_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_gen_driver_version_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_gen_maximum_total_size_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_gen_protocol_options_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_gen_mac_options_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_gen_media_connect_status_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_gen_maximum_send_packets_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_gen_vendor_driver_version_hdl(struct oid_par_priv *poid_par_priv); ++ ++ ++/* OID Handler for Segment 2 */ ++NDIS_STATUS oid_gen_physical_medium_hdl(struct oid_par_priv *poid_par_priv); ++ ++/* OID Handler for Segment 3 */ ++NDIS_STATUS oid_gen_xmit_ok_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_gen_rcv_ok_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_gen_xmit_error_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_gen_rcv_error_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_gen_rcv_no_buffer_hdl(struct oid_par_priv *poid_par_priv); ++ ++ ++/* OID Handler for Segment 4 */ ++NDIS_STATUS oid_802_3_permanent_address_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_3_current_address_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_3_multicast_list_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_3_maximum_list_size_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_3_mac_options_hdl(struct oid_par_priv *poid_par_priv); ++ ++ ++ ++/* OID Handler for Segment 5 */ ++NDIS_STATUS oid_802_3_rcv_error_alignment_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_3_xmit_one_collision_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_3_xmit_more_collisions_hdl(struct oid_par_priv *poid_par_priv); ++ ++ ++/* OID Handler for Segment 6 */ ++NDIS_STATUS oid_802_3_xmit_deferred_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_3_xmit_max_collisions_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_3_rcv_overrun_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_3_xmit_underrun_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_3_xmit_heartbeat_failure_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_3_xmit_times_crs_lost_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_3_xmit_late_collisions_hdl(struct oid_par_priv *poid_par_priv); ++ ++ ++ ++/* OID Handler for Segment 7 */ ++NDIS_STATUS oid_pnp_capabilities_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_pnp_set_power_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_pnp_query_power_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_pnp_add_wake_up_pattern_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_pnp_remove_wake_up_pattern_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_pnp_wake_up_pattern_list_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_pnp_enable_wake_up_hdl(struct oid_par_priv *poid_par_priv); ++ ++ ++ ++/* OID Handler for Segment 8 */ ++NDIS_STATUS oid_802_11_bssid_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_11_ssid_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_11_infrastructure_mode_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_11_add_wep_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_11_remove_wep_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_11_disassociate_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_11_authentication_mode_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_11_privacy_filter_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_11_bssid_list_scan_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_11_encryption_status_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_11_reload_defaults_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_11_add_key_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_11_remove_key_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_11_association_information_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_11_test_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_11_media_stream_mode_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_11_capability_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_11_pmkid_hdl(struct oid_par_priv *poid_par_priv); ++ ++ ++ ++ ++ ++/* OID Handler for Segment 9 */ ++NDIS_STATUS oid_802_11_network_types_supported_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_11_network_type_in_use_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_11_tx_power_level_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_11_rssi_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_11_rssi_trigger_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_11_fragmentation_threshold_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_11_rts_threshold_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_11_number_of_antennas_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_11_rx_antenna_selected_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_11_tx_antenna_selected_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_11_supported_rates_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_11_desired_rates_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_11_configuration_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_11_power_mode_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_802_11_bssid_list_hdl(struct oid_par_priv *poid_par_priv); ++ ++ ++/* OID Handler for Segment 10 */ ++NDIS_STATUS oid_802_11_statistics_hdl(struct oid_par_priv *poid_par_priv); ++ ++ ++/* OID Handler for Segment ED */ ++NDIS_STATUS oid_rt_mh_vender_id_hdl(struct oid_par_priv *poid_par_priv); ++ ++void Set_802_3_MULTICAST_LIST(ADAPTER *pAdapter, UCHAR *MCListbuf, ULONG MCListlen, BOOLEAN bAcceptAllMulticast); ++ ++#endif/* end of PLATFORM_WINDOWS */ ++ ++#if defined(PLATFORM_LINUX) && defined(CONFIG_WIRELESS_EXT) ++extern struct iw_handler_def rtw_handlers_def; ++#endif ++ ++extern void rtw_request_wps_pbc_event(_adapter *padapter); ++ ++extern NDIS_STATUS drv_query_info( ++ IN _nic_hdl MiniportAdapterContext, ++ IN NDIS_OID Oid, ++ IN void *InformationBuffer, ++ IN u32 InformationBufferLength, ++ OUT u32 *BytesWritten, ++ OUT u32 *BytesNeeded ++); ++ ++extern NDIS_STATUS drv_set_info( ++ IN _nic_hdl MiniportAdapterContext, ++ IN NDIS_OID Oid, ++ IN void *InformationBuffer, ++ IN u32 InformationBufferLength, ++ OUT u32 *BytesRead, ++ OUT u32 *BytesNeeded ++); ++ ++#ifdef CONFIG_APPEND_VENDOR_IE_ENABLE ++extern int rtw_vendor_ie_get_raw_data(struct net_device *, u32, char *, u32); ++extern int rtw_vendor_ie_get_data(struct net_device*, int , char*); ++extern int rtw_vendor_ie_get(struct net_device *, struct iw_request_info *, union iwreq_data *, char *); ++extern int rtw_vendor_ie_set(struct net_device*, struct iw_request_info*, union iwreq_data*, char*); ++#endif ++ ++#endif /* #ifndef __INC_CEINFO_ */ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_ioctl_query.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_ioctl_query.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_ioctl_query.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_ioctl_query.h 2021-03-07 18:16:17.090957755 +0200 +@@ -0,0 +1,25 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++#ifndef _RTW_IOCTL_QUERY_H_ ++#define _RTW_IOCTL_QUERY_H_ ++ ++ ++#ifdef PLATFORM_WINDOWS ++u8 query_802_11_capability(_adapter *padapter, u8 *pucBuf, u32 *pulOutLen); ++u8 query_802_11_association_information(_adapter *padapter, PNDIS_802_11_ASSOCIATION_INFORMATION pAssocInfo); ++#endif ++ ++ ++#endif +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_ioctl_rtl.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_ioctl_rtl.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_ioctl_rtl.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_ioctl_rtl.h 2021-03-07 18:16:17.090957755 +0200 +@@ -0,0 +1,75 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++#ifndef _RTW_IOCTL_RTL_H_ ++#define _RTW_IOCTL_RTL_H_ ++ ++ ++/* ************** oid_rtl_seg_01_01 ************** */ ++NDIS_STATUS oid_rt_get_signal_quality_hdl(struct oid_par_priv *poid_par_priv);/* 84 */ ++NDIS_STATUS oid_rt_get_small_packet_crc_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_get_middle_packet_crc_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_get_large_packet_crc_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_get_tx_retry_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_get_rx_retry_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_get_rx_total_packet_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_get_tx_beacon_ok_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_get_tx_beacon_err_hdl(struct oid_par_priv *poid_par_priv); ++ ++NDIS_STATUS oid_rt_pro_set_fw_dig_state_hdl(struct oid_par_priv *poid_par_priv); /* 8a */ ++NDIS_STATUS oid_rt_pro_set_fw_ra_state_hdl(struct oid_par_priv *poid_par_priv); /* 8b */ ++ ++NDIS_STATUS oid_rt_get_rx_icv_err_hdl(struct oid_par_priv *poid_par_priv);/* 93 */ ++NDIS_STATUS oid_rt_set_encryption_algorithm_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_get_preamble_mode_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_get_ap_ip_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_get_channelplan_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_set_channelplan_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_set_preamble_mode_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_set_bcn_intvl_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_dedicate_probe_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_get_total_tx_bytes_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_get_total_rx_bytes_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_current_tx_power_level_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_get_enc_key_mismatch_count_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_get_enc_key_match_count_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_get_channel_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_get_hardware_radio_off_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_get_key_mismatch_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_supported_wireless_mode_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_get_channel_list_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_get_scan_in_progress_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_forced_data_rate_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_wireless_mode_for_scan_list_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_get_bss_wireless_mode_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_scan_with_magic_packet_hdl(struct oid_par_priv *poid_par_priv); ++ ++/* ************** oid_rtl_seg_01_03 section start ************** */ ++NDIS_STATUS oid_rt_ap_get_associated_station_list_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_ap_switch_into_ap_mode_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_ap_supported_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_ap_set_passphrase_hdl(struct oid_par_priv *poid_par_priv); ++ ++/* oid_rtl_seg_01_11 */ ++NDIS_STATUS oid_rt_pro_rf_write_registry_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_pro_rf_read_registry_hdl(struct oid_par_priv *poid_par_priv); ++ ++/* ************** oid_rtl_seg_03_00 section start ************** */ ++NDIS_STATUS oid_rt_get_connect_state_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_set_default_key_id_hdl(struct oid_par_priv *poid_par_priv); ++ ++ ++ ++ ++#endif +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_ioctl_set.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_ioctl_set.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_ioctl_set.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_ioctl_set.h 2021-03-07 18:16:17.090957755 +0200 +@@ -0,0 +1,67 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++#ifndef __RTW_IOCTL_SET_H_ ++#define __RTW_IOCTL_SET_H_ ++ ++ ++typedef u8 NDIS_802_11_PMKID_VALUE[16]; ++ ++typedef struct _BSSIDInfo { ++ NDIS_802_11_MAC_ADDRESS BSSID; ++ NDIS_802_11_PMKID_VALUE PMKID; ++} BSSIDInfo, *PBSSIDInfo; ++ ++ ++#ifdef PLATFORM_OS_XP ++typedef struct _NDIS_802_11_PMKID { ++ u32 Length; ++ u32 BSSIDInfoCount; ++ BSSIDInfo BSSIDInfo[1]; ++} NDIS_802_11_PMKID, *PNDIS_802_11_PMKID; ++#endif ++ ++ ++#ifdef PLATFORM_WINDOWS ++u8 rtw_set_802_11_reload_defaults(_adapter *padapter, NDIS_802_11_RELOAD_DEFAULTS reloadDefaults); ++u8 rtw_set_802_11_test(_adapter *padapter, NDIS_802_11_TEST *test); ++u8 rtw_set_802_11_pmkid(_adapter *pdapter, NDIS_802_11_PMKID *pmkid); ++ ++u8 rtw_pnp_set_power_sleep(_adapter *padapter); ++u8 rtw_pnp_set_power_wakeup(_adapter *padapter); ++ ++void rtw_pnp_resume_wk(void *context); ++void rtw_pnp_sleep_wk(void *context); ++ ++#endif ++ ++u8 rtw_set_802_11_authentication_mode(_adapter *pdapter, NDIS_802_11_AUTHENTICATION_MODE authmode); ++u8 rtw_set_802_11_bssid(_adapter *padapter, u8 *bssid); ++u8 rtw_set_802_11_add_wep(_adapter *padapter, NDIS_802_11_WEP *wep); ++u8 rtw_set_802_11_disassociate(_adapter *padapter); ++u8 rtw_set_802_11_bssid_list_scan(_adapter *padapter, struct sitesurvey_parm *pparm); ++u8 rtw_set_802_11_infrastructure_mode(_adapter *padapter, NDIS_802_11_NETWORK_INFRASTRUCTURE networktype, u8 flags); ++u8 rtw_set_802_11_ssid(_adapter *padapter, NDIS_802_11_SSID *ssid); ++u8 rtw_set_802_11_connect(_adapter *padapter, u8 *bssid, NDIS_802_11_SSID *ssid); ++ ++u8 rtw_validate_bssid(u8 *bssid); ++u8 rtw_validate_ssid(NDIS_802_11_SSID *ssid); ++ ++u16 rtw_get_cur_max_rate(_adapter *adapter); ++int rtw_set_scan_mode(_adapter *adapter, RT_SCAN_TYPE scan_mode); ++int rtw_set_channel_plan(_adapter *adapter, u8 channel_plan); ++int rtw_set_country(_adapter *adapter, const char *country_code); ++int rtw_set_band(_adapter *adapter, u8 band); ++ ++#endif +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_io.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_io.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_io.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_io.h 2021-03-07 18:16:17.090957755 +0200 @@ -0,0 +1,569 @@ +/****************************************************************************** + * @@ -400365,521 +397293,9 @@ index 000000000..cafb12df6 + rtw_read32(_a, _b) + +#endif /* _RTL8711_IO_H_ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_ioctl.h linux-5.8/3rdparty/rtl8812au/include/rtw_ioctl.h -new file mode 100644 -index 000000000..4924751c2 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_ioctl.h -@@ -0,0 +1,319 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+#ifndef _RTW_IOCTL_H_ -+#define _RTW_IOCTL_H_ -+ -+#ifndef PLATFORM_WINDOWS -+/* 00 - Success -+* 11 - Error */ -+#define STATUS_SUCCESS (0x00000000L) -+#define STATUS_PENDING (0x00000103L) -+ -+#define STATUS_UNSUCCESSFUL (0xC0000001L) -+#define STATUS_INSUFFICIENT_RESOURCES (0xC000009AL) -+#define STATUS_NOT_SUPPORTED (0xC00000BBL) -+ -+#define NDIS_STATUS_SUCCESS ((NDIS_STATUS)STATUS_SUCCESS) -+#define NDIS_STATUS_PENDING ((NDIS_STATUS)STATUS_PENDING) -+#define NDIS_STATUS_NOT_RECOGNIZED ((NDIS_STATUS)0x00010001L) -+#define NDIS_STATUS_NOT_COPIED ((NDIS_STATUS)0x00010002L) -+#define NDIS_STATUS_NOT_ACCEPTED ((NDIS_STATUS)0x00010003L) -+#define NDIS_STATUS_CALL_ACTIVE ((NDIS_STATUS)0x00010007L) -+ -+#define NDIS_STATUS_FAILURE ((NDIS_STATUS)STATUS_UNSUCCESSFUL) -+#define NDIS_STATUS_RESOURCES ((NDIS_STATUS)STATUS_INSUFFICIENT_RESOURCES) -+#define NDIS_STATUS_CLOSING ((NDIS_STATUS)0xC0010002L) -+#define NDIS_STATUS_BAD_VERSION ((NDIS_STATUS)0xC0010004L) -+#define NDIS_STATUS_BAD_CHARACTERISTICS ((NDIS_STATUS)0xC0010005L) -+#define NDIS_STATUS_ADAPTER_NOT_FOUND ((NDIS_STATUS)0xC0010006L) -+#define NDIS_STATUS_OPEN_FAILED ((NDIS_STATUS)0xC0010007L) -+#define NDIS_STATUS_DEVICE_FAILED ((NDIS_STATUS)0xC0010008L) -+#define NDIS_STATUS_MULTICAST_FULL ((NDIS_STATUS)0xC0010009L) -+#define NDIS_STATUS_MULTICAST_EXISTS ((NDIS_STATUS)0xC001000AL) -+#define NDIS_STATUS_MULTICAST_NOT_FOUND ((NDIS_STATUS)0xC001000BL) -+#define NDIS_STATUS_REQUEST_ABORTED ((NDIS_STATUS)0xC001000CL) -+#define NDIS_STATUS_RESET_IN_PROGRESS ((NDIS_STATUS)0xC001000DL) -+#define NDIS_STATUS_CLOSING_INDICATING ((NDIS_STATUS)0xC001000EL) -+#define NDIS_STATUS_NOT_SUPPORTED ((NDIS_STATUS)STATUS_NOT_SUPPORTED) -+#define NDIS_STATUS_INVALID_PACKET ((NDIS_STATUS)0xC001000FL) -+#define NDIS_STATUS_OPEN_LIST_FULL ((NDIS_STATUS)0xC0010010L) -+#define NDIS_STATUS_ADAPTER_NOT_READY ((NDIS_STATUS)0xC0010011L) -+#define NDIS_STATUS_ADAPTER_NOT_OPEN ((NDIS_STATUS)0xC0010012L) -+#define NDIS_STATUS_NOT_INDICATING ((NDIS_STATUS)0xC0010013L) -+#define NDIS_STATUS_INVALID_LENGTH ((NDIS_STATUS)0xC0010014L) -+#define NDIS_STATUS_INVALID_DATA ((NDIS_STATUS)0xC0010015L) -+#define NDIS_STATUS_BUFFER_TOO_SHORT ((NDIS_STATUS)0xC0010016L) -+#define NDIS_STATUS_INVALID_OID ((NDIS_STATUS)0xC0010017L) -+#define NDIS_STATUS_ADAPTER_REMOVED ((NDIS_STATUS)0xC0010018L) -+#define NDIS_STATUS_UNSUPPORTED_MEDIA ((NDIS_STATUS)0xC0010019L) -+#define NDIS_STATUS_GROUP_ADDRESS_IN_USE ((NDIS_STATUS)0xC001001AL) -+#define NDIS_STATUS_FILE_NOT_FOUND ((NDIS_STATUS)0xC001001BL) -+#define NDIS_STATUS_ERROR_READING_FILE ((NDIS_STATUS)0xC001001CL) -+#define NDIS_STATUS_ALREADY_MAPPED ((NDIS_STATUS)0xC001001DL) -+#define NDIS_STATUS_RESOURCE_CONFLICT ((NDIS_STATUS)0xC001001EL) -+#define NDIS_STATUS_NO_CABLE ((NDIS_STATUS)0xC001001FL) -+ -+#define NDIS_STATUS_INVALID_SAP ((NDIS_STATUS)0xC0010020L) -+#define NDIS_STATUS_SAP_IN_USE ((NDIS_STATUS)0xC0010021L) -+#define NDIS_STATUS_INVALID_ADDRESS ((NDIS_STATUS)0xC0010022L) -+#define NDIS_STATUS_VC_NOT_ACTIVATED ((NDIS_STATUS)0xC0010023L) -+#define NDIS_STATUS_DEST_OUT_OF_ORDER ((NDIS_STATUS)0xC0010024L) /* cause 27 */ -+#define NDIS_STATUS_VC_NOT_AVAILABLE ((NDIS_STATUS)0xC0010025L) /* cause 35, 45 */ -+#define NDIS_STATUS_CELLRATE_NOT_AVAILABLE ((NDIS_STATUS)0xC0010026L) /* cause 37 */ -+#define NDIS_STATUS_INCOMPATABLE_QOS ((NDIS_STATUS)0xC0010027L) /* cause 49 */ -+#define NDIS_STATUS_AAL_PARAMS_UNSUPPORTED ((NDIS_STATUS)0xC0010028L) /* cause 93 */ -+#define NDIS_STATUS_NO_ROUTE_TO_DESTINATION ((NDIS_STATUS)0xC0010029L) /* cause 3 */ -+#endif /* #ifndef PLATFORM_WINDOWS */ -+ -+ -+#ifndef OID_802_11_CAPABILITY -+ #define OID_802_11_CAPABILITY 0x0d010122 -+#endif -+ -+#ifndef OID_802_11_PMKID -+ #define OID_802_11_PMKID 0x0d010123 -+#endif -+ -+ -+/* For DDK-defined OIDs */ -+#define OID_NDIS_SEG1 0x00010100 -+#define OID_NDIS_SEG2 0x00010200 -+#define OID_NDIS_SEG3 0x00020100 -+#define OID_NDIS_SEG4 0x01010100 -+#define OID_NDIS_SEG5 0x01020100 -+#define OID_NDIS_SEG6 0x01020200 -+#define OID_NDIS_SEG7 0xFD010100 -+#define OID_NDIS_SEG8 0x0D010100 -+#define OID_NDIS_SEG9 0x0D010200 -+#define OID_NDIS_SEG10 0x0D020200 -+ -+#define SZ_OID_NDIS_SEG1 23 -+#define SZ_OID_NDIS_SEG2 3 -+#define SZ_OID_NDIS_SEG3 6 -+#define SZ_OID_NDIS_SEG4 6 -+#define SZ_OID_NDIS_SEG5 4 -+#define SZ_OID_NDIS_SEG6 8 -+#define SZ_OID_NDIS_SEG7 7 -+#define SZ_OID_NDIS_SEG8 36 -+#define SZ_OID_NDIS_SEG9 24 -+#define SZ_OID_NDIS_SEG10 19 -+ -+/* For Realtek-defined OIDs */ -+#define OID_MP_SEG1 0xFF871100 -+#define OID_MP_SEG2 0xFF818000 -+ -+#define OID_MP_SEG3 0xFF818700 -+#define OID_MP_SEG4 0xFF011100 -+ -+enum oid_type { -+ QUERY_OID, -+ SET_OID -+}; -+ -+struct oid_funs_node { -+ unsigned int oid_start; /* the starting number for OID */ -+ unsigned int oid_end; /* the ending number for OID */ -+ struct oid_obj_priv *node_array; -+ unsigned int array_sz; /* the size of node_array */ -+ int query_counter; /* count the number of query hits for this segment */ -+ int set_counter; /* count the number of set hits for this segment */ -+}; -+ -+struct oid_par_priv { -+ void *adapter_context; -+ NDIS_OID oid; -+ void *information_buf; -+ u32 information_buf_len; -+ u32 *bytes_rw; -+ u32 *bytes_needed; -+ enum oid_type type_of_oid; -+ u32 dbg; -+}; -+ -+struct oid_obj_priv { -+ unsigned char dbg; /* 0: without OID debug message 1: with OID debug message */ -+ NDIS_STATUS(*oidfuns)(struct oid_par_priv *poid_par_priv); -+}; -+ -+#if (defined(CONFIG_MP_INCLUDED) && defined(_RTW_MP_IOCTL_C_)) || \ -+ (defined(PLATFORM_WINDOWS) && defined(_RTW_IOCTL_RTL_C_)) -+static NDIS_STATUS oid_null_function(struct oid_par_priv *poid_par_priv) -+{ -+ return NDIS_STATUS_SUCCESS; -+} -+#endif -+ -+#ifdef PLATFORM_WINDOWS -+ -+int TranslateNdisPsToRtPs(IN NDIS_802_11_POWER_MODE ndisPsMode); -+ -+/* OID Handler for Segment 1 */ -+NDIS_STATUS oid_gen_supported_list_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_gen_hardware_status_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_gen_media_supported_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_gen_media_in_use_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_gen_maximum_lookahead_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_gen_maximum_frame_size_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_gen_link_speed_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_gen_transmit_buffer_space_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_gen_receive_buffer_space_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_gen_transmit_block_size_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_gen_receive_block_size_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_gen_vendor_id_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_gen_vendor_description_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_gen_current_packet_filter_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_gen_current_lookahead_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_gen_driver_version_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_gen_maximum_total_size_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_gen_protocol_options_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_gen_mac_options_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_gen_media_connect_status_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_gen_maximum_send_packets_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_gen_vendor_driver_version_hdl(struct oid_par_priv *poid_par_priv); -+ -+ -+/* OID Handler for Segment 2 */ -+NDIS_STATUS oid_gen_physical_medium_hdl(struct oid_par_priv *poid_par_priv); -+ -+/* OID Handler for Segment 3 */ -+NDIS_STATUS oid_gen_xmit_ok_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_gen_rcv_ok_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_gen_xmit_error_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_gen_rcv_error_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_gen_rcv_no_buffer_hdl(struct oid_par_priv *poid_par_priv); -+ -+ -+/* OID Handler for Segment 4 */ -+NDIS_STATUS oid_802_3_permanent_address_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_3_current_address_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_3_multicast_list_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_3_maximum_list_size_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_3_mac_options_hdl(struct oid_par_priv *poid_par_priv); -+ -+ -+ -+/* OID Handler for Segment 5 */ -+NDIS_STATUS oid_802_3_rcv_error_alignment_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_3_xmit_one_collision_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_3_xmit_more_collisions_hdl(struct oid_par_priv *poid_par_priv); -+ -+ -+/* OID Handler for Segment 6 */ -+NDIS_STATUS oid_802_3_xmit_deferred_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_3_xmit_max_collisions_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_3_rcv_overrun_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_3_xmit_underrun_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_3_xmit_heartbeat_failure_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_3_xmit_times_crs_lost_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_3_xmit_late_collisions_hdl(struct oid_par_priv *poid_par_priv); -+ -+ -+ -+/* OID Handler for Segment 7 */ -+NDIS_STATUS oid_pnp_capabilities_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_pnp_set_power_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_pnp_query_power_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_pnp_add_wake_up_pattern_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_pnp_remove_wake_up_pattern_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_pnp_wake_up_pattern_list_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_pnp_enable_wake_up_hdl(struct oid_par_priv *poid_par_priv); -+ -+ -+ -+/* OID Handler for Segment 8 */ -+NDIS_STATUS oid_802_11_bssid_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_11_ssid_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_11_infrastructure_mode_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_11_add_wep_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_11_remove_wep_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_11_disassociate_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_11_authentication_mode_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_11_privacy_filter_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_11_bssid_list_scan_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_11_encryption_status_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_11_reload_defaults_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_11_add_key_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_11_remove_key_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_11_association_information_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_11_test_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_11_media_stream_mode_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_11_capability_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_11_pmkid_hdl(struct oid_par_priv *poid_par_priv); -+ -+ -+ -+ -+ -+/* OID Handler for Segment 9 */ -+NDIS_STATUS oid_802_11_network_types_supported_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_11_network_type_in_use_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_11_tx_power_level_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_11_rssi_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_11_rssi_trigger_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_11_fragmentation_threshold_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_11_rts_threshold_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_11_number_of_antennas_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_11_rx_antenna_selected_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_11_tx_antenna_selected_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_11_supported_rates_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_11_desired_rates_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_11_configuration_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_11_power_mode_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_802_11_bssid_list_hdl(struct oid_par_priv *poid_par_priv); -+ -+ -+/* OID Handler for Segment 10 */ -+NDIS_STATUS oid_802_11_statistics_hdl(struct oid_par_priv *poid_par_priv); -+ -+ -+/* OID Handler for Segment ED */ -+NDIS_STATUS oid_rt_mh_vender_id_hdl(struct oid_par_priv *poid_par_priv); -+ -+void Set_802_3_MULTICAST_LIST(ADAPTER *pAdapter, UCHAR *MCListbuf, ULONG MCListlen, BOOLEAN bAcceptAllMulticast); -+ -+#endif/* end of PLATFORM_WINDOWS */ -+ -+#if defined(PLATFORM_LINUX) && defined(CONFIG_WIRELESS_EXT) -+extern struct iw_handler_def rtw_handlers_def; -+#endif -+ -+extern void rtw_request_wps_pbc_event(_adapter *padapter); -+ -+extern NDIS_STATUS drv_query_info( -+ IN _nic_hdl MiniportAdapterContext, -+ IN NDIS_OID Oid, -+ IN void *InformationBuffer, -+ IN u32 InformationBufferLength, -+ OUT u32 *BytesWritten, -+ OUT u32 *BytesNeeded -+); -+ -+extern NDIS_STATUS drv_set_info( -+ IN _nic_hdl MiniportAdapterContext, -+ IN NDIS_OID Oid, -+ IN void *InformationBuffer, -+ IN u32 InformationBufferLength, -+ OUT u32 *BytesRead, -+ OUT u32 *BytesNeeded -+); -+ -+#ifdef CONFIG_APPEND_VENDOR_IE_ENABLE -+extern int rtw_vendor_ie_get_raw_data(struct net_device *, u32, char *, u32); -+extern int rtw_vendor_ie_get_data(struct net_device*, int , char*); -+extern int rtw_vendor_ie_get(struct net_device *, struct iw_request_info *, union iwreq_data *, char *); -+extern int rtw_vendor_ie_set(struct net_device*, struct iw_request_info*, union iwreq_data*, char*); -+#endif -+ -+#endif /* #ifndef __INC_CEINFO_ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_ioctl_query.h linux-5.8/3rdparty/rtl8812au/include/rtw_ioctl_query.h -new file mode 100644 -index 000000000..cc7b557ee ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_ioctl_query.h -@@ -0,0 +1,25 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+#ifndef _RTW_IOCTL_QUERY_H_ -+#define _RTW_IOCTL_QUERY_H_ -+ -+ -+#ifdef PLATFORM_WINDOWS -+u8 query_802_11_capability(_adapter *padapter, u8 *pucBuf, u32 *pulOutLen); -+u8 query_802_11_association_information(_adapter *padapter, PNDIS_802_11_ASSOCIATION_INFORMATION pAssocInfo); -+#endif -+ -+ -+#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_ioctl_rtl.h linux-5.8/3rdparty/rtl8812au/include/rtw_ioctl_rtl.h -new file mode 100644 -index 000000000..2df8713ad ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_ioctl_rtl.h -@@ -0,0 +1,75 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+#ifndef _RTW_IOCTL_RTL_H_ -+#define _RTW_IOCTL_RTL_H_ -+ -+ -+/* ************** oid_rtl_seg_01_01 ************** */ -+NDIS_STATUS oid_rt_get_signal_quality_hdl(struct oid_par_priv *poid_par_priv);/* 84 */ -+NDIS_STATUS oid_rt_get_small_packet_crc_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_get_middle_packet_crc_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_get_large_packet_crc_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_get_tx_retry_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_get_rx_retry_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_get_rx_total_packet_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_get_tx_beacon_ok_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_get_tx_beacon_err_hdl(struct oid_par_priv *poid_par_priv); -+ -+NDIS_STATUS oid_rt_pro_set_fw_dig_state_hdl(struct oid_par_priv *poid_par_priv); /* 8a */ -+NDIS_STATUS oid_rt_pro_set_fw_ra_state_hdl(struct oid_par_priv *poid_par_priv); /* 8b */ -+ -+NDIS_STATUS oid_rt_get_rx_icv_err_hdl(struct oid_par_priv *poid_par_priv);/* 93 */ -+NDIS_STATUS oid_rt_set_encryption_algorithm_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_get_preamble_mode_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_get_ap_ip_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_get_channelplan_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_set_channelplan_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_set_preamble_mode_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_set_bcn_intvl_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_dedicate_probe_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_get_total_tx_bytes_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_get_total_rx_bytes_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_current_tx_power_level_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_get_enc_key_mismatch_count_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_get_enc_key_match_count_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_get_channel_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_get_hardware_radio_off_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_get_key_mismatch_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_supported_wireless_mode_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_get_channel_list_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_get_scan_in_progress_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_forced_data_rate_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_wireless_mode_for_scan_list_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_get_bss_wireless_mode_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_scan_with_magic_packet_hdl(struct oid_par_priv *poid_par_priv); -+ -+/* ************** oid_rtl_seg_01_03 section start ************** */ -+NDIS_STATUS oid_rt_ap_get_associated_station_list_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_ap_switch_into_ap_mode_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_ap_supported_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_ap_set_passphrase_hdl(struct oid_par_priv *poid_par_priv); -+ -+/* oid_rtl_seg_01_11 */ -+NDIS_STATUS oid_rt_pro_rf_write_registry_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_pro_rf_read_registry_hdl(struct oid_par_priv *poid_par_priv); -+ -+/* ************** oid_rtl_seg_03_00 section start ************** */ -+NDIS_STATUS oid_rt_get_connect_state_hdl(struct oid_par_priv *poid_par_priv); -+NDIS_STATUS oid_rt_set_default_key_id_hdl(struct oid_par_priv *poid_par_priv); -+ -+ -+ -+ -+#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_ioctl_set.h linux-5.8/3rdparty/rtl8812au/include/rtw_ioctl_set.h -new file mode 100644 -index 000000000..2af4a54cc ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_ioctl_set.h -@@ -0,0 +1,67 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+#ifndef __RTW_IOCTL_SET_H_ -+#define __RTW_IOCTL_SET_H_ -+ -+ -+typedef u8 NDIS_802_11_PMKID_VALUE[16]; -+ -+typedef struct _BSSIDInfo { -+ NDIS_802_11_MAC_ADDRESS BSSID; -+ NDIS_802_11_PMKID_VALUE PMKID; -+} BSSIDInfo, *PBSSIDInfo; -+ -+ -+#ifdef PLATFORM_OS_XP -+typedef struct _NDIS_802_11_PMKID { -+ u32 Length; -+ u32 BSSIDInfoCount; -+ BSSIDInfo BSSIDInfo[1]; -+} NDIS_802_11_PMKID, *PNDIS_802_11_PMKID; -+#endif -+ -+ -+#ifdef PLATFORM_WINDOWS -+u8 rtw_set_802_11_reload_defaults(_adapter *padapter, NDIS_802_11_RELOAD_DEFAULTS reloadDefaults); -+u8 rtw_set_802_11_test(_adapter *padapter, NDIS_802_11_TEST *test); -+u8 rtw_set_802_11_pmkid(_adapter *pdapter, NDIS_802_11_PMKID *pmkid); -+ -+u8 rtw_pnp_set_power_sleep(_adapter *padapter); -+u8 rtw_pnp_set_power_wakeup(_adapter *padapter); -+ -+void rtw_pnp_resume_wk(void *context); -+void rtw_pnp_sleep_wk(void *context); -+ -+#endif -+ -+u8 rtw_set_802_11_authentication_mode(_adapter *pdapter, NDIS_802_11_AUTHENTICATION_MODE authmode); -+u8 rtw_set_802_11_bssid(_adapter *padapter, u8 *bssid); -+u8 rtw_set_802_11_add_wep(_adapter *padapter, NDIS_802_11_WEP *wep); -+u8 rtw_set_802_11_disassociate(_adapter *padapter); -+u8 rtw_set_802_11_bssid_list_scan(_adapter *padapter, struct sitesurvey_parm *pparm); -+u8 rtw_set_802_11_infrastructure_mode(_adapter *padapter, NDIS_802_11_NETWORK_INFRASTRUCTURE networktype, u8 flags); -+u8 rtw_set_802_11_ssid(_adapter *padapter, NDIS_802_11_SSID *ssid); -+u8 rtw_set_802_11_connect(_adapter *padapter, u8 *bssid, NDIS_802_11_SSID *ssid); -+ -+u8 rtw_validate_bssid(u8 *bssid); -+u8 rtw_validate_ssid(NDIS_802_11_SSID *ssid); -+ -+u16 rtw_get_cur_max_rate(_adapter *adapter); -+int rtw_set_scan_mode(_adapter *adapter, RT_SCAN_TYPE scan_mode); -+int rtw_set_channel_plan(_adapter *adapter, u8 channel_plan); -+int rtw_set_country(_adapter *adapter, const char *country_code); -+int rtw_set_band(_adapter *adapter, u8 band); -+ -+#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_iol.h linux-5.8/3rdparty/rtl8812au/include/rtw_iol.h -new file mode 100644 -index 000000000..fa35a59c7 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_iol.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_iol.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_iol.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_iol.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_iol.h 2021-03-07 18:16:17.090957755 +0200 @@ -0,0 +1,131 @@ +/****************************************************************************** + * @@ -401012,11 +397428,9 @@ index 000000000..fa35a59c7 + + +#endif /* __RTW_IOL_H_ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_mcc.h linux-5.8/3rdparty/rtl8812au/include/rtw_mcc.h -new file mode 100644 -index 000000000..718036cb2 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_mcc.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_mcc.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_mcc.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_mcc.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_mcc.h 2021-03-07 18:16:17.090957755 +0200 @@ -0,0 +1,271 @@ +/****************************************************************************** + * @@ -401289,11 +397703,9 @@ index 000000000..718036cb2 +u8 rtw_set_mcc_duration_cmd(_adapter *adapter, u8 type, u8 val); +#endif /* _RTW_MCC_H_ */ +#endif /* CONFIG_MCC_MODE */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_mem.h linux-5.8/3rdparty/rtl8812au/include/rtw_mem.h -new file mode 100644 -index 000000000..229028c35 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_mem.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_mem.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_mem.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_mem.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_mem.h 2021-03-07 18:16:17.090957755 +0200 @@ -0,0 +1,36 @@ +/****************************************************************************** + * @@ -401331,11 +397743,9 @@ index 000000000..229028c35 + + +#endif /* __RTW_MEM_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_mi.h linux-5.8/3rdparty/rtl8812au/include/rtw_mi.h -new file mode 100644 -index 000000000..26db46bff ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_mi.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_mi.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_mi.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_mi.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_mi.h 2021-03-07 18:16:17.090957755 +0200 @@ -0,0 +1,306 @@ +/****************************************************************************** + * @@ -401643,11 +398053,1324 @@ index 000000000..26db46bff +void rtw_mi_update_ap_bmc_camid(_adapter *padapter, u8 camid_a, u8 camid_b); + +#endif /*__RTW_MI_H_*/ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_mlme.h linux-5.8/3rdparty/rtl8812au/include/rtw_mlme.h -new file mode 100644 -index 000000000..cdac712cd ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_mlme.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_mlme_ext.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_mlme_ext.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_mlme_ext.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_mlme_ext.h 2021-03-07 18:16:17.090957755 +0200 +@@ -0,0 +1,1311 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++#ifndef __RTW_MLME_EXT_H_ ++#define __RTW_MLME_EXT_H_ ++ ++ ++/* Commented by Albert 20101105 ++ * Increase the SURVEY_TO value from 100 to 150 ( 100ms to 150ms ) ++ * The Realtek 8188CE SoftAP will spend around 100ms to send the probe response after receiving the probe request. ++ * So, this driver tried to extend the dwell time for each scanning channel. ++ * This will increase the chance to receive the probe response from SoftAP. */ ++#define SURVEY_TO (100) ++ ++#define REAUTH_TO (300) /* (50) */ ++#define REASSOC_TO (300) /* (50) */ ++/* #define DISCONNECT_TO (3000) */ ++#define ADDBA_TO (2000) ++ ++#define LINKED_TO (1) /* unit:2 sec, 1x2 = 2 sec */ ++ ++#define REAUTH_LIMIT (4) ++#define REASSOC_LIMIT (4) ++#define READDBA_LIMIT (2) ++ ++#ifdef CONFIG_GSPI_HCI ++ #define ROAMING_LIMIT 5 ++#else ++ #define ROAMING_LIMIT 8 ++#endif ++/* #define IOCMD_REG0 0x10250370 */ ++/* #define IOCMD_REG1 0x10250374 */ ++/* #define IOCMD_REG2 0x10250378 */ ++ ++/* #define FW_DYNAMIC_FUN_SWITCH 0x10250364 */ ++ ++/* #define WRITE_BB_CMD 0xF0000001 */ ++/* #define SET_CHANNEL_CMD 0xF3000000 */ ++/* #define UPDATE_RA_CMD 0xFD0000A2 */ ++ ++#define _HW_STATE_NOLINK_ 0x00 ++#define _HW_STATE_ADHOC_ 0x01 ++#define _HW_STATE_STATION_ 0x02 ++#define _HW_STATE_AP_ 0x03 ++#define _HW_STATE_MONITOR_ 0x04 ++ ++ ++#define _1M_RATE_ 0 ++#define _2M_RATE_ 1 ++#define _5M_RATE_ 2 ++#define _11M_RATE_ 3 ++#define _6M_RATE_ 4 ++#define _9M_RATE_ 5 ++#define _12M_RATE_ 6 ++#define _18M_RATE_ 7 ++#define _24M_RATE_ 8 ++#define _36M_RATE_ 9 ++#define _48M_RATE_ 10 ++#define _54M_RATE_ 11 ++ ++/******************************************************** ++MCS rate definitions ++*********************************************************/ ++#define MCS_RATE_1R (0x000000ff) ++#define MCS_RATE_2R (0x0000ffff) ++#define MCS_RATE_3R (0x00ffffff) ++#define MCS_RATE_4R (0xffffffff) ++#define MCS_RATE_2R_13TO15_OFF (0x00001fff) ++ ++ ++extern unsigned char RTW_WPA_OUI[]; ++extern unsigned char WMM_OUI[]; ++extern unsigned char WPS_OUI[]; ++extern unsigned char WFD_OUI[]; ++extern unsigned char P2P_OUI[]; ++ ++extern unsigned char WMM_INFO_OUI[]; ++extern unsigned char WMM_PARA_OUI[]; ++ ++typedef struct _RT_CHANNEL_PLAN { ++ unsigned char Channel[MAX_CHANNEL_NUM]; ++ unsigned char Len; ++} RT_CHANNEL_PLAN, *PRT_CHANNEL_PLAN; ++ ++enum Associated_AP { ++ atherosAP = 0, ++ broadcomAP = 1, ++ ciscoAP = 2, ++ marvellAP = 3, ++ ralinkAP = 4, ++ realtekAP = 5, ++ airgocapAP = 6, ++ unknownAP = 7, ++ maxAP, ++}; ++ ++typedef enum _HT_IOT_PEER { ++ HT_IOT_PEER_UNKNOWN = 0, ++ HT_IOT_PEER_REALTEK = 1, ++ HT_IOT_PEER_REALTEK_92SE = 2, ++ HT_IOT_PEER_BROADCOM = 3, ++ HT_IOT_PEER_RALINK = 4, ++ HT_IOT_PEER_ATHEROS = 5, ++ HT_IOT_PEER_CISCO = 6, ++ HT_IOT_PEER_MERU = 7, ++ HT_IOT_PEER_MARVELL = 8, ++ HT_IOT_PEER_REALTEK_SOFTAP = 9,/* peer is RealTek SOFT_AP, by Bohn, 2009.12.17 */ ++ HT_IOT_PEER_SELF_SOFTAP = 10, /* Self is SoftAP */ ++ HT_IOT_PEER_AIRGO = 11, ++ HT_IOT_PEER_INTEL = 12, ++ HT_IOT_PEER_RTK_APCLIENT = 13, ++ HT_IOT_PEER_REALTEK_81XX = 14, ++ HT_IOT_PEER_REALTEK_WOW = 15, ++ HT_IOT_PEER_REALTEK_JAGUAR_BCUTAP = 16, ++ HT_IOT_PEER_REALTEK_JAGUAR_CCUTAP = 17, ++ HT_IOT_PEER_MAX = 18 ++} HT_IOT_PEER_E, *PHTIOT_PEER_E; ++ ++ ++typedef enum _RT_HT_INF0_CAP { ++ RT_HT_CAP_USE_TURBO_AGGR = 0x01, ++ RT_HT_CAP_USE_LONG_PREAMBLE = 0x02, ++ RT_HT_CAP_USE_AMPDU = 0x04, ++ RT_HT_CAP_USE_WOW = 0x8, ++ RT_HT_CAP_USE_SOFTAP = 0x10, ++ RT_HT_CAP_USE_92SE = 0x20, ++ RT_HT_CAP_USE_88C_92C = 0x40, ++ RT_HT_CAP_USE_AP_CLIENT_MODE = 0x80, /* AP team request to reserve this bit, by Emily */ ++} RT_HT_INF0_CAPBILITY, *PRT_HT_INF0_CAPBILITY; ++ ++typedef enum _RT_HT_INF1_CAP { ++ RT_HT_CAP_USE_VIDEO_CLIENT = 0x01, ++ RT_HT_CAP_USE_JAGUAR_BCUT = 0x02, ++ RT_HT_CAP_USE_JAGUAR_CCUT = 0x04, ++} RT_HT_INF1_CAPBILITY, *PRT_HT_INF1_CAPBILITY; ++ ++struct mlme_handler { ++ unsigned int num; ++ char *str; ++ unsigned int (*func)(_adapter *padapter, union recv_frame *precv_frame); ++}; ++ ++struct action_handler { ++ unsigned int num; ++ char *str; ++ unsigned int (*func)(_adapter *padapter, union recv_frame *precv_frame); ++}; ++ ++enum SCAN_STATE { ++ SCAN_DISABLE = 0, ++ SCAN_START = 1, ++ SCAN_PS_ANNC_WAIT = 2, ++ SCAN_ENTER = 3, ++ SCAN_PROCESS = 4, ++ ++ /* backop */ ++ SCAN_BACKING_OP = 5, ++ SCAN_BACK_OP = 6, ++ SCAN_LEAVING_OP = 7, ++ SCAN_LEAVE_OP = 8, ++ ++ /* SW antenna diversity (before linked) */ ++ SCAN_SW_ANTDIV_BL = 9, ++ ++ /* legacy p2p */ ++ SCAN_TO_P2P_LISTEN = 10, ++ SCAN_P2P_LISTEN = 11, ++ ++ SCAN_COMPLETE = 12, ++ SCAN_STATE_MAX, ++}; ++ ++const char *scan_state_str(u8 state); ++ ++enum ss_backop_flag { ++ SS_BACKOP_EN = BIT0, /* backop when linked */ ++ SS_BACKOP_EN_NL = BIT1, /* backop even when no linked */ ++ ++ SS_BACKOP_PS_ANNC = BIT4, ++ SS_BACKOP_TX_RESUME = BIT5, ++}; ++ ++struct ss_res { ++ u8 state; ++ u8 next_state; /* will set to state on next cmd hdl */ ++ int bss_cnt; ++ int channel_idx; ++#ifdef CONFIG_DFS ++ u8 dfs_ch_ssid_scan; ++#endif ++ int scan_mode; ++ u16 scan_ch_ms; ++ u32 scan_timeout_ms; ++ u8 rx_ampdu_accept; ++ u8 rx_ampdu_size; ++ u8 igi_scan; ++ u8 igi_before_scan; /* used for restoring IGI value without enable DIG & FA_CNT */ ++#ifdef CONFIG_SCAN_BACKOP ++ u8 backop_flags_sta; /* policy for station mode*/ ++ #ifdef CONFIG_AP_MODE ++ u8 backop_flags_ap; /* policy for ap mode */ ++ #endif ++ #ifdef CONFIG_RTW_MESH ++ u8 backop_flags_mesh; /* policy for mesh mode */ ++ #endif ++ u8 backop_flags; /* per backop runtime decision */ ++ u8 scan_cnt; ++ u8 scan_cnt_max; ++ systime backop_time; /* the start time of backop */ ++ u16 backop_ms; ++#endif ++#if defined(CONFIG_ANTENNA_DIVERSITY) || defined(DBG_SCAN_SW_ANTDIV_BL) ++ u8 is_sw_antdiv_bl_scan; ++#endif ++ u8 ssid_num; ++ u8 ch_num; ++ NDIS_802_11_SSID ssid[RTW_SSID_SCAN_AMOUNT]; ++ struct rtw_ieee80211_channel ch[RTW_CHANNEL_SCAN_AMOUNT]; ++ ++ u32 token; /* 0: use to identify caller */ ++ u16 duration; /* 0: use default */ ++ u8 igi; /* 0: use defalut */ ++ u8 bw; /* 0: use default */ ++}; ++ ++/* #define AP_MODE 0x0C */ ++/* #define STATION_MODE 0x08 */ ++/* #define AD_HOC_MODE 0x04 */ ++/* #define NO_LINK_MODE 0x00 */ ++ ++#define WIFI_FW_NULL_STATE _HW_STATE_NOLINK_ ++#define WIFI_FW_STATION_STATE _HW_STATE_STATION_ ++#define WIFI_FW_AP_STATE _HW_STATE_AP_ ++#define WIFI_FW_ADHOC_STATE _HW_STATE_ADHOC_ ++ ++#define WIFI_FW_PRE_LINK 0x00000800 ++#define WIFI_FW_AUTH_NULL 0x00000100 ++#define WIFI_FW_AUTH_STATE 0x00000200 ++#define WIFI_FW_AUTH_SUCCESS 0x00000400 ++ ++#define WIFI_FW_ASSOC_STATE 0x00002000 ++#define WIFI_FW_ASSOC_SUCCESS 0x00004000 ++ ++#define WIFI_FW_LINKING_STATE (WIFI_FW_AUTH_NULL | WIFI_FW_AUTH_STATE | WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE) ++ ++#ifdef CONFIG_TDLS ++enum TDLS_option { ++ TDLS_ESTABLISHED = 1, ++ TDLS_ISSUE_PTI, ++ TDLS_CH_SW_RESP, ++ TDLS_CH_SW_PREPARE, ++ TDLS_CH_SW_START, ++ TDLS_CH_SW_TO_OFF_CHNL, ++ TDLS_CH_SW_TO_BASE_CHNL_UNSOLICITED, ++ TDLS_CH_SW_TO_BASE_CHNL, ++ TDLS_CH_SW_END_TO_BASE_CHNL, ++ TDLS_CH_SW_END, ++ TDLS_RS_RCR, ++ TDLS_TEARDOWN_STA, ++ TDLS_TEARDOWN_STA_NO_WAIT, ++ TDLS_TEARDOWN_STA_LOCALLY, ++ TDLS_TEARDOWN_STA_LOCALLY_POST, ++ maxTDLS, ++}; ++ ++#endif /* CONFIG_TDLS */ ++ ++#ifndef NL80211_AUTHTYPE_SAE ++#define NL80211_AUTHTYPE_SAE 4 ++#endif ++ ++/* ++ * Usage: ++ * When one iface acted as AP mode and the other iface is STA mode and scanning, ++ * it should switch back to AP's operating channel periodically. ++ * Parameters info: ++ * When the driver scanned RTW_SCAN_NUM_OF_CH channels, it would switch back to AP's operating channel for ++ * RTW_BACK_OP_CH_MS milliseconds. ++ * Example: ++ * For chip supports 2.4G + 5GHz and AP mode is operating in channel 1, ++ * RTW_SCAN_NUM_OF_CH is 8, RTW_BACK_OP_CH_MS is 300 ++ * When it's STA mode gets set_scan command, ++ * it would ++ * 1. Doing the scan on channel 1.2.3.4.5.6.7.8 ++ * 2. Back to channel 1 for 300 milliseconds ++ * 3. Go through doing site survey on channel 9.10.11.36.40.44.48.52 ++ * 4. Back to channel 1 for 300 milliseconds ++ * 5. ... and so on, till survey done. ++ */ ++#if defined(CONFIG_ATMEL_RC_PATCH) ++ #define RTW_SCAN_NUM_OF_CH 2 ++ #define RTW_BACK_OP_CH_MS 200 ++#else ++ #define RTW_SCAN_NUM_OF_CH 3 ++ #define RTW_BACK_OP_CH_MS 400 ++#endif ++ ++#define RTW_IP_ADDR_LEN 4 ++#define RTW_IPv6_ADDR_LEN 16 ++ ++struct mlme_ext_info { ++ u32 state; ++#ifdef CONFIG_MI_WITH_MBSSID_CAM ++ u8 hw_media_state; ++#endif ++ u32 reauth_count; ++ u32 reassoc_count; ++ u32 link_count; ++ u32 auth_seq; ++ u32 auth_algo; /* 802.11 auth, could be open, shared, auto */ ++ u16 auth_status; ++ u32 authModeToggle; ++ u32 enc_algo;/* encrypt algorithm; */ ++ u32 key_index; /* this is only valid for legendary wep, 0~3 for key id. */ ++ u32 iv; ++ u8 chg_txt[128]; ++ u16 aid; ++ u16 bcn_interval; ++ u16 capability; ++ u8 assoc_AP_vendor; ++ u8 slotTime; ++ u8 preamble_mode; ++ u8 WMM_enable; ++ u8 ERP_enable; ++ u8 ERP_IE; ++ u8 HT_enable; ++ u8 HT_caps_enable; ++ u8 HT_info_enable; ++ u8 HT_protection; ++ u8 turboMode_cts2self; ++ u8 turboMode_rtsen; ++ u8 SM_PS; ++ u8 agg_enable_bitmap; ++ u8 ADDBA_retry_count; ++ u8 candidate_tid_bitmap; ++ u8 dialogToken; ++ /* Accept ADDBA Request */ ++ BOOLEAN bAcceptAddbaReq; ++ u8 bwmode_updated; ++ u8 hidden_ssid_mode; ++ u8 VHT_enable; ++ ++ u8 ip_addr[RTW_IP_ADDR_LEN]; ++ u8 ip6_addr[RTW_IPv6_ADDR_LEN]; ++ ++ struct ADDBA_request ADDBA_req; ++ struct WMM_para_element WMM_param; ++ struct HT_caps_element HT_caps; ++ struct HT_info_element HT_info; ++ WLAN_BSSID_EX network;/* join network or bss_network, if in ap mode, it is the same to cur_network.network */ ++#ifdef ROKU_PRIVATE ++ /*infra mode, store supported rates from AssocRsp*/ ++ NDIS_802_11_RATES_EX SupportedRates_infra_ap; ++ u8 ht_vht_received;/*ht_vht_received used to show debug msg BIT(0):HT BIT(1):VHT */ ++#endif /* ROKU_PRIVATE */ ++}; ++ ++/* The channel information about this channel including joining, scanning, and power constraints. */ ++typedef struct _RT_CHANNEL_INFO { ++ u8 ChannelNum; /* The channel number. */ ++ RT_SCAN_TYPE ScanType; /* Scan type such as passive or active scan. */ ++ /* u16 ScanPeriod; */ /* Listen time in millisecond in this channel. */ ++ /* s32 MaxTxPwrDbm; */ /* Max allowed tx power. */ ++ /* u32 ExInfo; */ /* Extended Information for this channel. */ ++#ifdef CONFIG_FIND_BEST_CHANNEL ++ u32 rx_count; ++#endif ++#ifdef CONFIG_DFS ++ #ifdef CONFIG_DFS_MASTER ++ systime non_ocp_end_time; ++ #endif ++ u8 hidden_bss_cnt; /* per scan count */ ++#endif ++} RT_CHANNEL_INFO, *PRT_CHANNEL_INFO; ++ ++#define CAC_TIME_MS (60*1000) ++#define CAC_TIME_CE_MS (10*60*1000) ++#define NON_OCP_TIME_MS (30*60*1000) ++ ++#if CONFIG_TXPWR_LIMIT ++void rtw_txpwr_init_regd(struct rf_ctl_t *rfctl); ++#endif ++void rtw_rfctl_init(_adapter *adapter); ++void rtw_rfctl_deinit(_adapter *adapter); ++ ++#ifdef CONFIG_DFS_MASTER ++struct rf_ctl_t; ++#define CH_IS_NON_OCP(rt_ch_info) (rtw_time_after((rt_ch_info)->non_ocp_end_time, rtw_get_current_time())) ++bool rtw_is_cac_reset_needed(struct rf_ctl_t *rfctl, u8 ch, u8 bw, u8 offset); ++bool _rtw_rfctl_overlap_radar_detect_ch(struct rf_ctl_t *rfctl, u8 ch, u8 bw, u8 offset); ++bool rtw_rfctl_overlap_radar_detect_ch(struct rf_ctl_t *rfctl); ++bool rtw_rfctl_is_tx_blocked_by_ch_waiting(struct rf_ctl_t *rfctl); ++bool rtw_chset_is_chbw_non_ocp(RT_CHANNEL_INFO *ch_set, u8 ch, u8 bw, u8 offset); ++bool rtw_chset_is_ch_non_ocp(RT_CHANNEL_INFO *ch_set, u8 ch); ++void rtw_chset_update_non_ocp(RT_CHANNEL_INFO *ch_set, u8 ch, u8 bw, u8 offset); ++void rtw_chset_update_non_ocp_ms(RT_CHANNEL_INFO *ch_set, u8 ch, u8 bw, u8 offset, int ms); ++u32 rtw_get_ch_waiting_ms(struct rf_ctl_t *rfctl, u8 ch, u8 bw, u8 offset, u32 *r_non_ocp_ms, u32 *r_cac_ms); ++void rtw_reset_cac(struct rf_ctl_t *rfctl, u8 ch, u8 bw, u8 offset); ++u32 rtw_force_stop_cac(struct rf_ctl_t *rfctl, u32 timeout_ms); ++#else ++#define CH_IS_NON_OCP(rt_ch_info) 0 ++#define rtw_chset_is_chbw_non_ocp(ch_set, ch, bw, offset) _FALSE ++#define rtw_chset_is_ch_non_ocp(ch_set, ch) _FALSE ++#define rtw_rfctl_is_tx_blocked_by_ch_waiting(rfctl) _FALSE ++#endif ++ ++enum { ++ RTW_CHF_2G = BIT0, ++ RTW_CHF_5G = BIT1, ++ RTW_CHF_DFS = BIT2, ++ RTW_CHF_LONG_CAC = BIT3, ++ RTW_CHF_NON_DFS = BIT4, ++ RTW_CHF_NON_LONG_CAC = BIT5, ++ RTW_CHF_NON_OCP = BIT6, ++}; ++ ++bool rtw_choose_shortest_waiting_ch(struct rf_ctl_t *rfctl, u8 sel_ch, u8 max_bw ++ , u8 *dec_ch, u8 *dec_bw, u8 *dec_offset ++ , u8 d_flags, u8 cur_ch, u8 same_band_prefer, u8 mesh_only); ++ ++void dump_chset(void *sel, RT_CHANNEL_INFO *ch_set); ++void dump_cur_chset(void *sel, struct rf_ctl_t *rfctl); ++ ++int rtw_chset_search_ch(RT_CHANNEL_INFO *ch_set, const u32 ch); ++u8 rtw_chset_is_chbw_valid(RT_CHANNEL_INFO *ch_set, u8 ch, u8 bw, u8 offset); ++void rtw_chset_sync_chbw(RT_CHANNEL_INFO *ch_set, u8 *req_ch, u8 *req_bw, u8 *req_offset ++ , u8 *g_ch, u8 *g_bw, u8 *g_offset); ++ ++bool rtw_mlme_band_check(_adapter *adapter, const u32 ch); ++ ++ ++enum { ++ BAND_24G = BIT0, ++ BAND_5G = BIT1, ++}; ++void RTW_SET_SCAN_BAND_SKIP(_adapter *padapter, int skip_band); ++void RTW_CLR_SCAN_BAND_SKIP(_adapter *padapter, int skip_band); ++int RTW_GET_SCAN_BAND_SKIP(_adapter *padapter); ++ ++bool rtw_mlme_ignore_chan(_adapter *adapter, const u32 ch); ++ ++/* P2P_MAX_REG_CLASSES - Maximum number of regulatory classes */ ++#define P2P_MAX_REG_CLASSES 10 ++ ++/* P2P_MAX_REG_CLASS_CHANNELS - Maximum number of channels per regulatory class */ ++#define P2P_MAX_REG_CLASS_CHANNELS 20 ++ ++/* struct p2p_channels - List of supported channels */ ++struct p2p_channels { ++ /* struct p2p_reg_class - Supported regulatory class */ ++ struct p2p_reg_class { ++ /* reg_class - Regulatory class (IEEE 802.11-2007, Annex J) */ ++ u8 reg_class; ++ ++ /* channel - Supported channels */ ++ u8 channel[P2P_MAX_REG_CLASS_CHANNELS]; ++ ++ /* channels - Number of channel entries in use */ ++ size_t channels; ++ } reg_class[P2P_MAX_REG_CLASSES]; ++ ++ /* reg_classes - Number of reg_class entries in use */ ++ size_t reg_classes; ++}; ++ ++struct p2p_oper_class_map { ++ enum hw_mode {IEEE80211G, IEEE80211A} mode; ++ u8 op_class; ++ u8 min_chan; ++ u8 max_chan; ++ u8 inc; ++ enum { BW20, BW40PLUS, BW40MINUS } bw; ++}; ++ ++struct mlme_ext_priv { ++ _adapter *padapter; ++ u8 mlmeext_init; ++ ATOMIC_T event_seq; ++ u16 mgnt_seq; ++#ifdef CONFIG_IEEE80211W ++ u16 sa_query_seq; ++#endif ++ /* struct fw_priv fwpriv; */ ++ ++ unsigned char cur_channel; ++ unsigned char cur_bwmode; ++ unsigned char cur_ch_offset;/* PRIME_CHNL_OFFSET */ ++ unsigned char cur_wireless_mode; /* NETWORK_TYPE */ ++ ++ unsigned char basicrate[NumRates]; ++ unsigned char datarate[NumRates]; ++#ifdef CONFIG_80211N_HT ++ unsigned char default_supported_mcs_set[16]; ++#endif ++ ++ struct ss_res sitesurvey_res; ++ struct mlme_ext_info mlmext_info;/* for sta/adhoc mode, including current scanning/connecting/connected related info. ++ * for ap mode, network includes ap's cap_info */ ++ _timer survey_timer; ++ _timer link_timer; ++ ++#ifdef CONFIG_RTW_REPEATER_SON ++ _timer rson_scan_timer; ++#endif ++#ifdef CONFIG_RTW_80211R ++ _timer ft_link_timer; ++ _timer ft_roam_timer; ++#endif ++ ++ systime last_scan_time; ++ u8 scan_abort; ++ u8 join_abort; ++ u8 tx_rate; /* TXRATE when USERATE is set. */ ++ ++ u32 retry; /* retry for issue probereq */ ++ ++ u64 TSFValue; ++ u32 bcn_cnt; ++ u32 last_bcn_cnt; ++ u8 cur_bcn_cnt;/*2s*/ ++ u8 dtim;/*DTIM Period*/ ++#ifdef DBG_RX_BCN ++ u8 tim[4]; ++#endif ++#ifdef CONFIG_BCN_RECV_TIME ++ u16 bcn_rx_time; ++#endif ++#ifdef CONFIG_AP_MODE ++ unsigned char bstart_bss; ++#endif ++ ++#ifdef CONFIG_80211D ++ u8 update_channel_plan_by_ap_done; ++#endif ++ /* recv_decache check for Action_public frame */ ++ u8 action_public_dialog_token; ++ u16 action_public_rxseq; ++ ++ /* #ifdef CONFIG_ACTIVE_KEEP_ALIVE_CHECK */ ++ u8 active_keep_alive_check; ++ /* #endif */ ++#ifdef DBG_FIXED_CHAN ++ u8 fixed_chan; ++#endif ++ ++ u8 tsf_update_required:1; ++ u8 en_hw_update_tsf:1; /* set hw sync bcn tsf register or not */ ++ systime tsf_update_pause_stime; ++ u8 tsf_update_pause_factor; /* num of bcn intervals to stay TSF update pause status */ ++ u8 tsf_update_restore_factor; /* num of bcn interval to stay TSF update restore status */ ++#ifdef CONFIG_SUPPORT_STATIC_SMPS ++ u8 ssmps_en; ++ u16 ssmps_tx_tp_th;/*Mbps*/ ++ u16 ssmps_rx_tp_th;/*Mbps*/ ++ #ifdef DBG_STATIC_SMPS ++ u8 ssmps_test; ++ u8 ssmps_test_en; ++ #endif ++#endif ++#ifdef CONFIG_CTRL_TXSS_BY_TP ++ u8 txss_ctrl_en; ++ u16 txss_tp_th;/*Mbps*/ ++ u8 txss_tp_chk_cnt;/*unit 2s*/ ++ u8 txss_1ss; ++ u8 txss_momi_type_bk; ++#endif ++}; ++ ++struct support_rate_handler { ++ u8 rate; ++ bool basic; ++ bool existence; ++}; ++ ++static inline u8 check_mlmeinfo_state(struct mlme_ext_priv *plmeext, sint state) ++{ ++ if ((plmeext->mlmext_info.state & 0x03) == state) ++ return _TRUE; ++ ++ return _FALSE; ++} ++ ++void sitesurvey_set_offch_state(_adapter *adapter, u8 scan_state); ++ ++#define mlmeext_msr(mlmeext) ((mlmeext)->mlmext_info.state & 0x03) ++#define mlmeext_scan_state(mlmeext) ((mlmeext)->sitesurvey_res.state) ++#define mlmeext_scan_state_str(mlmeext) scan_state_str((mlmeext)->sitesurvey_res.state) ++#define mlmeext_chk_scan_state(mlmeext, _state) ((mlmeext)->sitesurvey_res.state == (_state)) ++#define mlmeext_set_scan_state(mlmeext, _state) \ ++ do { \ ++ ((mlmeext)->sitesurvey_res.state = (_state)); \ ++ ((mlmeext)->sitesurvey_res.next_state = (_state)); \ ++ rtw_mi_update_iface_status(&((container_of(mlmeext, _adapter, mlmeextpriv)->mlmepriv)), 0); \ ++ /* RTW_INFO("set_scan_state:%s\n", scan_state_str(_state)); */ \ ++ sitesurvey_set_offch_state(container_of(mlmeext, _adapter, mlmeextpriv), _state); \ ++ } while (0) ++ ++#define mlmeext_scan_next_state(mlmeext) ((mlmeext)->sitesurvey_res.next_state) ++#define mlmeext_set_scan_next_state(mlmeext, _state) \ ++ do { \ ++ ((mlmeext)->sitesurvey_res.next_state = (_state)); \ ++ /* RTW_INFO("set_scan_next_state:%s\n", scan_state_str(_state)); */ \ ++ } while (0) ++ ++#ifdef CONFIG_SCAN_BACKOP ++#define mlmeext_scan_backop_flags(mlmeext) ((mlmeext)->sitesurvey_res.backop_flags) ++#define mlmeext_chk_scan_backop_flags(mlmeext, flags) ((mlmeext)->sitesurvey_res.backop_flags & (flags)) ++#define mlmeext_assign_scan_backop_flags(mlmeext, flags) \ ++ do { \ ++ ((mlmeext)->sitesurvey_res.backop_flags = (flags)); \ ++ RTW_INFO("assign_scan_backop_flags:0x%02x\n", (mlmeext)->sitesurvey_res.backop_flags); \ ++ } while (0) ++ ++#define mlmeext_scan_backop_flags_sta(mlmeext) ((mlmeext)->sitesurvey_res.backop_flags_sta) ++#define mlmeext_chk_scan_backop_flags_sta(mlmeext, flags) ((mlmeext)->sitesurvey_res.backop_flags_sta & (flags)) ++#define mlmeext_assign_scan_backop_flags_sta(mlmeext, flags) \ ++ do { \ ++ ((mlmeext)->sitesurvey_res.backop_flags_sta = (flags)); \ ++ } while (0) ++#else ++#define mlmeext_scan_backop_flags(mlmeext) (0) ++#define mlmeext_chk_scan_backop_flags(mlmeext, flags) (0) ++#define mlmeext_assign_scan_backop_flags(mlmeext, flags) do {} while (0) ++ ++#define mlmeext_scan_backop_flags_sta(mlmeext) (0) ++#define mlmeext_chk_scan_backop_flags_sta(mlmeext, flags) (0) ++#define mlmeext_assign_scan_backop_flags_sta(mlmeext, flags) do {} while (0) ++#endif /* CONFIG_SCAN_BACKOP */ ++ ++#if defined(CONFIG_SCAN_BACKOP) && defined(CONFIG_AP_MODE) ++#define mlmeext_scan_backop_flags_ap(mlmeext) ((mlmeext)->sitesurvey_res.backop_flags_ap) ++#define mlmeext_chk_scan_backop_flags_ap(mlmeext, flags) ((mlmeext)->sitesurvey_res.backop_flags_ap & (flags)) ++#define mlmeext_assign_scan_backop_flags_ap(mlmeext, flags) \ ++ do { \ ++ ((mlmeext)->sitesurvey_res.backop_flags_ap = (flags)); \ ++ } while (0) ++#else ++#define mlmeext_scan_backop_flags_ap(mlmeext) (0) ++#define mlmeext_chk_scan_backop_flags_ap(mlmeext, flags) (0) ++#define mlmeext_assign_scan_backop_flags_ap(mlmeext, flags) do {} while (0) ++#endif /* defined(CONFIG_SCAN_BACKOP) && defined(CONFIG_AP_MODE) */ ++ ++#if defined(CONFIG_SCAN_BACKOP) && defined(CONFIG_RTW_MESH) ++#define mlmeext_scan_backop_flags_mesh(mlmeext) ((mlmeext)->sitesurvey_res.backop_flags_mesh) ++#define mlmeext_chk_scan_backop_flags_mesh(mlmeext, flags) ((mlmeext)->sitesurvey_res.backop_flags_mesh & (flags)) ++#define mlmeext_assign_scan_backop_flags_mesh(mlmeext, flags) \ ++ do { \ ++ ((mlmeext)->sitesurvey_res.backop_flags_mesh = (flags)); \ ++ } while (0) ++#else ++#define mlmeext_scan_backop_flags_mesh(mlmeext) (0) ++#define mlmeext_chk_scan_backop_flags_mesh(mlmeext, flags) (0) ++#define mlmeext_assign_scan_backop_flags_mesh(mlmeext, flags) do {} while (0) ++#endif /* defined(CONFIG_SCAN_BACKOP) && defined(CONFIG_RTW_MESH) */ ++ ++u32 rtw_scan_timeout_decision(_adapter *padapter); ++ ++void init_mlme_default_rate_set(_adapter *padapter); ++int init_mlme_ext_priv(_adapter *padapter); ++int init_hw_mlme_ext(_adapter *padapter); ++void free_mlme_ext_priv(struct mlme_ext_priv *pmlmeext); ++extern struct xmit_frame *alloc_mgtxmitframe(struct xmit_priv *pxmitpriv); ++struct xmit_frame *alloc_mgtxmitframe_once(struct xmit_priv *pxmitpriv); ++ ++/* void fill_fwpriv(_adapter * padapter, struct fw_priv *pfwpriv); */ ++u8 judge_network_type(_adapter *padapter, unsigned char *rate, int ratelen); ++void get_rate_set(_adapter *padapter, unsigned char *pbssrate, int *bssrate_len); ++void set_mcs_rate_by_mask(u8 *mcs_set, u32 mask); ++void UpdateBrateTbl(_adapter *padapter, u8 *mBratesOS); ++void UpdateBrateTblForSoftAP(u8 *bssrateset, u32 bssratelen); ++void change_band_update_ie(_adapter *padapter, WLAN_BSSID_EX *pnetwork, u8 ch); ++ ++void Set_MSR(_adapter *padapter, u8 type); ++ ++void rtw_set_external_auth_status(_adapter *padapter, const void *data, int len); ++ ++u8 rtw_get_oper_ch(_adapter *adapter); ++void rtw_set_oper_ch(_adapter *adapter, u8 ch); ++u8 rtw_get_oper_bw(_adapter *adapter); ++void rtw_set_oper_bw(_adapter *adapter, u8 bw); ++u8 rtw_get_oper_choffset(_adapter *adapter); ++void rtw_set_oper_choffset(_adapter *adapter, u8 offset); ++u8 rtw_get_center_ch(u8 channel, u8 chnl_bw, u8 chnl_offset); ++systime rtw_get_on_oper_ch_time(_adapter *adapter); ++systime rtw_get_on_cur_ch_time(_adapter *adapter); ++ ++u8 rtw_get_offset_by_chbw(u8 ch, u8 bw, u8 *r_offset); ++ ++void set_channel_bwmode(_adapter *padapter, unsigned char channel, unsigned char channel_offset, unsigned short bwmode); ++ ++unsigned int decide_wait_for_beacon_timeout(unsigned int bcn_interval); ++ ++void _clear_cam_entry(_adapter *padapter, u8 entry); ++void write_cam_from_cache(_adapter *adapter, u8 id); ++void rtw_sec_cam_swap(_adapter *adapter, u8 cam_id_a, u8 cam_id_b); ++void rtw_clean_dk_section(_adapter *adapter); ++void rtw_clean_hw_dk_cam(_adapter *adapter); ++ ++/* modify both HW and cache */ ++void write_cam(_adapter *padapter, u8 id, u16 ctrl, u8 *mac, u8 *key); ++void clear_cam_entry(_adapter *padapter, u8 id); ++ ++/* modify cache only */ ++void write_cam_cache(_adapter *adapter, u8 id, u16 ctrl, u8 *mac, u8 *key); ++void clear_cam_cache(_adapter *adapter, u8 id); ++ ++void invalidate_cam_all(_adapter *padapter); ++void CAM_empty_entry(PADAPTER Adapter, u8 ucIndex); ++ ++void flush_all_cam_entry(_adapter *padapter); ++ ++BOOLEAN IsLegal5GChannel(PADAPTER Adapter, u8 channel); ++ ++void site_survey(_adapter *padapter, u8 survey_channel, RT_SCAN_TYPE ScanType); ++u8 collect_bss_info(_adapter *padapter, union recv_frame *precv_frame, WLAN_BSSID_EX *bssid); ++void update_network(WLAN_BSSID_EX *dst, WLAN_BSSID_EX *src, _adapter *padapter, bool update_ie); ++ ++u8 *get_my_bssid(WLAN_BSSID_EX *pnetwork); ++u16 get_beacon_interval(WLAN_BSSID_EX *bss); ++ ++int is_client_associated_to_ap(_adapter *padapter); ++int is_client_associated_to_ibss(_adapter *padapter); ++int is_IBSS_empty(_adapter *padapter); ++ ++unsigned char check_assoc_AP(u8 *pframe, uint len); ++void get_assoc_AP_Vendor(char *vendor, u8 assoc_AP_vendor); ++#ifdef CONFIG_RTS_FULL_BW ++void rtw_parse_sta_vendor_ie_8812(_adapter *adapter, struct sta_info *sta, u8 *tlv_ies, u16 tlv_ies_len); ++#endif/*CONFIG_RTS_FULL_BW*/ ++#ifdef CONFIG_80211AC_VHT ++unsigned char get_vht_mu_bfer_cap(u8 *pframe, uint len); ++#endif ++ ++int WMM_param_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE); ++#ifdef CONFIG_WFD ++void rtw_process_wfd_ie(_adapter *adapter, u8 *ie, u8 ie_len, const char *tag); ++void rtw_process_wfd_ies(_adapter *adapter, u8 *ies, u8 ies_len, const char *tag); ++#endif ++void WMMOnAssocRsp(_adapter *padapter); ++ ++void HT_caps_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE); ++#ifdef ROKU_PRIVATE ++void HT_caps_handler_infra_ap(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE); ++#endif ++void HT_info_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE); ++void HTOnAssocRsp(_adapter *padapter); ++ ++#ifdef ROKU_PRIVATE ++void Supported_rate_infra_ap(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE); ++void Extended_Supported_rate_infra_ap(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE); ++#endif ++ ++void ERP_IE_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE); ++void VCS_update(_adapter *padapter, struct sta_info *psta); ++void update_ldpc_stbc_cap(struct sta_info *psta); ++ ++bool rtw_validate_value(u16 EID, u8 *p, u16 len); ++bool hidden_ssid_ap(WLAN_BSSID_EX *snetwork); ++void rtw_absorb_ssid_ifneed(_adapter *padapter, WLAN_BSSID_EX *bssid, u8 *pframe); ++int rtw_get_bcn_keys(ADAPTER *Adapter, u8 *pframe, u32 packet_len, ++ struct beacon_keys *recv_beacon); ++int validate_beacon_len(u8 *pframe, uint len); ++void rtw_dump_bcn_keys(void *sel, struct beacon_keys *recv_beacon); ++int rtw_check_bcn_info(ADAPTER *Adapter, u8 *pframe, u32 packet_len); ++void update_beacon_info(_adapter *padapter, u8 *pframe, uint len, struct sta_info *psta); ++#ifdef CONFIG_DFS ++void process_csa_ie(_adapter *padapter, u8 *ies, uint ies_len); ++#endif /* CONFIG_DFS */ ++void update_capinfo(PADAPTER Adapter, u16 updateCap); ++void update_wireless_mode(_adapter *padapter); ++void update_tx_basic_rate(_adapter *padapter, u8 modulation); ++void update_sta_basic_rate(struct sta_info *psta, u8 wireless_mode); ++int rtw_ies_get_supported_rate(u8 *ies, uint ies_len, u8 *rate_set, u8 *rate_num); ++ ++/* for sta/adhoc mode */ ++void update_sta_info(_adapter *padapter, struct sta_info *psta); ++unsigned int update_basic_rate(unsigned char *ptn, unsigned int ptn_sz); ++unsigned int update_supported_rate(unsigned char *ptn, unsigned int ptn_sz); ++void Update_RA_Entry(_adapter *padapter, struct sta_info *psta); ++void set_sta_rate(_adapter *padapter, struct sta_info *psta); ++ ++unsigned int receive_disconnect(_adapter *padapter, unsigned char *MacAddr, unsigned short reason, u8 locally_generated); ++ ++unsigned char get_highest_rate_idx(u64 mask); ++unsigned char get_lowest_rate_idx_ex(u64 mask, int start_bit); ++#define get_lowest_rate_idx(mask) get_lowest_rate_idx_ex(mask, 0) ++ ++int support_short_GI(_adapter *padapter, struct HT_caps_element *pHT_caps, u8 bwmode); ++unsigned int is_ap_in_tkip(_adapter *padapter); ++unsigned int is_ap_in_wep(_adapter *padapter); ++unsigned int should_forbid_n_rate(_adapter *padapter); ++ ++void parsing_eapol_packet(_adapter *padapter, u8 *key_payload, struct sta_info *psta, u8 trx_type); ++ ++bool _rtw_camctl_chk_cap(_adapter *adapter, u8 cap); ++void _rtw_camctl_set_flags(_adapter *adapter, u32 flags); ++void rtw_camctl_set_flags(_adapter *adapter, u32 flags); ++void _rtw_camctl_clr_flags(_adapter *adapter, u32 flags); ++void rtw_camctl_clr_flags(_adapter *adapter, u32 flags); ++bool _rtw_camctl_chk_flags(_adapter *adapter, u32 flags); ++ ++struct sec_cam_bmp; ++void dump_sec_cam_map(void *sel, struct sec_cam_bmp *map, u8 max_num); ++void rtw_sec_cam_map_clr_all(struct sec_cam_bmp *map); ++ ++bool _rtw_camid_is_gk(_adapter *adapter, u8 cam_id); ++bool rtw_camid_is_gk(_adapter *adapter, u8 cam_id); ++s16 rtw_camid_search(_adapter *adapter, u8 *addr, s16 kid, s8 gk); ++s16 rtw_camid_alloc(_adapter *adapter, struct sta_info *sta, u8 kid, u8 gk, bool *used); ++void rtw_camid_free(_adapter *adapter, u8 cam_id); ++u8 rtw_get_sec_camid(_adapter *adapter, u8 max_bk_key_num, u8 *sec_key_id); ++ ++struct macid_bmp; ++struct macid_ctl_t; ++void dump_macid_map(void *sel, struct macid_bmp *map, u8 max_num); ++bool rtw_macid_is_set(struct macid_bmp *map, u8 id); ++void rtw_macid_map_clr(struct macid_bmp *map, u8 id); ++bool rtw_macid_is_used(struct macid_ctl_t *macid_ctl, u8 id); ++bool rtw_macid_is_bmc(struct macid_ctl_t *macid_ctl, u8 id); ++u8 rtw_macid_get_iface_bmp(struct macid_ctl_t *macid_ctl, u8 id); ++bool rtw_macid_is_iface_shared(struct macid_ctl_t *macid_ctl, u8 id); ++bool rtw_macid_is_iface_specific(struct macid_ctl_t *macid_ctl, u8 id, _adapter *adapter); ++s8 rtw_macid_get_ch_g(struct macid_ctl_t *macid_ctl, u8 id); ++void rtw_alloc_macid(_adapter *padapter, struct sta_info *psta); ++void rtw_release_macid(_adapter *padapter, struct sta_info *psta); ++u8 rtw_search_max_mac_id(_adapter *padapter); ++void rtw_macid_ctl_set_h2c_msr(struct macid_ctl_t *macid_ctl, u8 id, u8 h2c_msr); ++void rtw_macid_ctl_set_bw(struct macid_ctl_t *macid_ctl, u8 id, u8 bw); ++void rtw_macid_ctl_set_vht_en(struct macid_ctl_t *macid_ctl, u8 id, u8 en); ++void rtw_macid_ctl_set_rate_bmp0(struct macid_ctl_t *macid_ctl, u8 id, u32 bmp); ++void rtw_macid_ctl_set_rate_bmp1(struct macid_ctl_t *macid_ctl, u8 id, u32 bmp); ++void rtw_macid_ctl_init_sleep_reg(struct macid_ctl_t *macid_ctl, u16 m0, u16 m1, u16 m2, u16 m3); ++void rtw_macid_ctl_init(struct macid_ctl_t *macid_ctl); ++void rtw_macid_ctl_deinit(struct macid_ctl_t *macid_ctl); ++u8 rtw_iface_bcmc_id_get(_adapter *padapter); ++void rtw_iface_bcmc_id_set(_adapter *padapter, u8 mac_id); ++#if defined(DBG_CONFIG_ERROR_RESET) && defined(CONFIG_CONCURRENT_MODE) ++void rtw_iface_bcmc_sec_cam_map_restore(_adapter *adapter); ++#endif ++bool rtw_bmp_is_set(const u8 *bmp, u8 bmp_len, u8 id); ++void rtw_bmp_set(u8 *bmp, u8 bmp_len, u8 id); ++void rtw_bmp_clear(u8 *bmp, u8 bmp_len, u8 id); ++bool rtw_bmp_not_empty(const u8 *bmp, u8 bmp_len); ++bool rtw_bmp_not_empty_exclude_bit0(const u8 *bmp, u8 bmp_len); ++ ++#ifdef CONFIG_AP_MODE ++bool rtw_tim_map_is_set(_adapter *padapter, const u8 *map, u8 id); ++void rtw_tim_map_set(_adapter *padapter, u8 *map, u8 id); ++void rtw_tim_map_clear(_adapter *padapter, u8 *map, u8 id); ++bool rtw_tim_map_anyone_be_set(_adapter *padapter, const u8 *map); ++bool rtw_tim_map_anyone_be_set_exclude_aid0(_adapter *padapter, const u8 *map); ++#endif /* CONFIG_AP_MODE */ ++ ++u32 report_join_res(_adapter *padapter, int aid_res, u16 status); ++void report_survey_event(_adapter *padapter, union recv_frame *precv_frame); ++void report_surveydone_event(_adapter *padapter); ++u32 report_del_sta_event(_adapter *padapter, unsigned char *MacAddr, unsigned short reason, bool enqueue, u8 locally_generated); ++void report_add_sta_event(_adapter *padapter, unsigned char *MacAddr); ++bool rtw_port_switch_chk(_adapter *adapter); ++void report_wmm_edca_update(_adapter *padapter); ++ ++void beacon_timing_control(_adapter *padapter); ++u8 chk_bmc_sleepq_cmd(_adapter *padapter); ++extern u8 set_tx_beacon_cmd(_adapter *padapter); ++unsigned int setup_beacon_frame(_adapter *padapter, unsigned char *beacon_frame); ++void update_mgnt_tx_rate(_adapter *padapter, u8 rate); ++void update_monitor_frame_attrib(_adapter *padapter, struct pkt_attrib *pattrib); ++void update_mgntframe_attrib(_adapter *padapter, struct pkt_attrib *pattrib); ++void update_mgntframe_attrib_addr(_adapter *padapter, struct xmit_frame *pmgntframe); ++void dump_mgntframe(_adapter *padapter, struct xmit_frame *pmgntframe); ++s32 dump_mgntframe_and_wait(_adapter *padapter, struct xmit_frame *pmgntframe, int timeout_ms); ++s32 dump_mgntframe_and_wait_ack(_adapter *padapter, struct xmit_frame *pmgntframe); ++s32 dump_mgntframe_and_wait_ack_timeout(_adapter *padapter, struct xmit_frame *pmgntframe, int timeout_ms); ++ ++#ifdef CONFIG_P2P ++int get_reg_classes_full_count(struct p2p_channels *channel_list); ++void issue_probersp_p2p(_adapter *padapter, unsigned char *da); ++void issue_p2p_provision_request(_adapter *padapter, u8 *pssid, u8 ussidlen, u8 *pdev_raddr); ++void issue_p2p_GO_request(_adapter *padapter, u8 *raddr); ++void issue_probereq_p2p(_adapter *padapter, u8 *da); ++int issue_probereq_p2p_ex(_adapter *adapter, u8 *da, int try_cnt, int wait_ms); ++void issue_p2p_invitation_response(_adapter *padapter, u8 *raddr, u8 dialogToken, u8 success); ++void issue_p2p_invitation_request(_adapter *padapter, u8 *raddr); ++#endif /* CONFIG_P2P */ ++void issue_beacon(_adapter *padapter, int timeout_ms); ++void issue_probersp(_adapter *padapter, unsigned char *da, u8 is_valid_p2p_probereq); ++void _issue_assocreq(_adapter *padapter, u8 is_assoc); ++void issue_assocreq(_adapter *padapter); ++void issue_reassocreq(_adapter *padapter); ++void issue_asocrsp(_adapter *padapter, unsigned short status, struct sta_info *pstat, int pkt_type); ++void issue_auth(_adapter *padapter, struct sta_info *psta, unsigned short status); ++void issue_probereq(_adapter *padapter, const NDIS_802_11_SSID *pssid, const u8 *da); ++s32 issue_probereq_ex(_adapter *padapter, const NDIS_802_11_SSID *pssid, const u8 *da, u8 ch, bool append_wps, int try_cnt, int wait_ms); ++int issue_nulldata(_adapter *padapter, unsigned char *da, unsigned int power_mode, int try_cnt, int wait_ms); ++int issue_qos_nulldata(_adapter *padapter, unsigned char *da, u16 tid, u8 ps, int try_cnt, int wait_ms); ++int issue_deauth(_adapter *padapter, unsigned char *da, unsigned short reason); ++int issue_deauth_ex(_adapter *padapter, u8 *da, unsigned short reason, int try_cnt, int wait_ms); ++void issue_action_spct_ch_switch(_adapter *padapter, u8 *ra, u8 new_ch, u8 ch_offset); ++void issue_addba_req(_adapter *adapter, unsigned char *ra, u8 tid); ++void issue_addba_rsp(_adapter *adapter, unsigned char *ra, u8 tid, u16 status, u8 size); ++u8 issue_addba_rsp_wait_ack(_adapter *adapter, unsigned char *ra, u8 tid, u16 status, u8 size, int try_cnt, int wait_ms); ++void issue_del_ba(_adapter *adapter, unsigned char *ra, u8 tid, u16 reason, u8 initiator); ++int issue_del_ba_ex(_adapter *adapter, unsigned char *ra, u8 tid, u16 reason, u8 initiator, int try_cnt, int wait_ms); ++void issue_action_BSSCoexistPacket(_adapter *padapter); ++ ++#ifdef CONFIG_IEEE80211W ++void issue_action_SA_Query(_adapter *padapter, unsigned char *raddr, unsigned char action, unsigned short tid, u8 key_type); ++int issue_deauth_11w(_adapter *padapter, unsigned char *da, unsigned short reason, u8 key_type); ++#endif /* CONFIG_IEEE80211W */ ++int issue_action_SM_PS(_adapter *padapter , unsigned char *raddr , u8 NewMimoPsMode); ++int issue_action_SM_PS_wait_ack(_adapter *padapter, unsigned char *raddr, u8 NewMimoPsMode, int try_cnt, int wait_ms); ++ ++unsigned int send_delba_sta_tid(_adapter *adapter, u8 initiator, struct sta_info *sta, u8 tid, u8 force); ++unsigned int send_delba_sta_tid_wait_ack(_adapter *adapter, u8 initiator, struct sta_info *sta, u8 tid, u8 force); ++ ++unsigned int send_delba(_adapter *padapter, u8 initiator, u8 *addr); ++unsigned int send_beacon(_adapter *padapter); ++ ++void start_clnt_assoc(_adapter *padapter); ++void start_clnt_auth(_adapter *padapter); ++void start_clnt_join(_adapter *padapter); ++void start_create_ibss(_adapter *padapter); ++ ++unsigned int OnAssocReq(_adapter *padapter, union recv_frame *precv_frame); ++unsigned int OnAssocRsp(_adapter *padapter, union recv_frame *precv_frame); ++unsigned int OnProbeReq(_adapter *padapter, union recv_frame *precv_frame); ++unsigned int OnProbeRsp(_adapter *padapter, union recv_frame *precv_frame); ++unsigned int DoReserved(_adapter *padapter, union recv_frame *precv_frame); ++unsigned int OnBeacon(_adapter *padapter, union recv_frame *precv_frame); ++unsigned int OnAtim(_adapter *padapter, union recv_frame *precv_frame); ++unsigned int OnDisassoc(_adapter *padapter, union recv_frame *precv_frame); ++unsigned int OnAuth(_adapter *padapter, union recv_frame *precv_frame); ++unsigned int OnAuthClient(_adapter *padapter, union recv_frame *precv_frame); ++unsigned int OnDeAuth(_adapter *padapter, union recv_frame *precv_frame); ++unsigned int OnAction(_adapter *padapter, union recv_frame *precv_frame); ++ ++unsigned int on_action_spct(_adapter *padapter, union recv_frame *precv_frame); ++unsigned int OnAction_qos(_adapter *padapter, union recv_frame *precv_frame); ++unsigned int OnAction_dls(_adapter *padapter, union recv_frame *precv_frame); ++#ifdef CONFIG_RTW_WNM ++unsigned int on_action_wnm(_adapter *adapter, union recv_frame *rframe); ++#endif ++ ++#define RX_AMPDU_ACCEPT_INVALID 0xFF ++#define RX_AMPDU_SIZE_INVALID 0xFF ++ ++enum rx_ampdu_reason { ++ RX_AMPDU_DRV_FIXED = 1, ++ RX_AMPDU_BTCOEX = 2, /* not used, because BTCOEX has its own variable management */ ++ RX_AMPDU_DRV_SCAN = 3, ++}; ++u8 rtw_rx_ampdu_size(_adapter *adapter); ++bool rtw_rx_ampdu_is_accept(_adapter *adapter); ++bool rtw_rx_ampdu_set_size(_adapter *adapter, u8 size, u8 reason); ++bool rtw_rx_ampdu_set_accept(_adapter *adapter, u8 accept, u8 reason); ++u8 rx_ampdu_apply_sta_tid(_adapter *adapter, struct sta_info *sta, u8 tid, u8 accept, u8 size); ++u8 rx_ampdu_size_sta_limit(_adapter *adapter, struct sta_info *sta); ++u8 rx_ampdu_apply_sta(_adapter *adapter, struct sta_info *sta, u8 accept, u8 size); ++u16 rtw_rx_ampdu_apply(_adapter *adapter); ++ ++unsigned int OnAction_back(_adapter *padapter, union recv_frame *precv_frame); ++unsigned int on_action_public(_adapter *padapter, union recv_frame *precv_frame); ++unsigned int OnAction_ft(_adapter *padapter, union recv_frame *precv_frame); ++unsigned int OnAction_ht(_adapter *padapter, union recv_frame *precv_frame); ++#ifdef CONFIG_IEEE80211W ++unsigned int OnAction_sa_query(_adapter *padapter, union recv_frame *precv_frame); ++#endif /* CONFIG_IEEE80211W */ ++unsigned int on_action_rm(_adapter *padapter, union recv_frame *precv_frame); ++unsigned int OnAction_wmm(_adapter *padapter, union recv_frame *precv_frame); ++unsigned int OnAction_vht(_adapter *padapter, union recv_frame *precv_frame); ++unsigned int OnAction_p2p(_adapter *padapter, union recv_frame *precv_frame); ++ ++#ifdef CONFIG_RTW_80211R ++void rtw_ft_update_bcn(_adapter *padapter, union recv_frame *precv_frame); ++void rtw_ft_start_clnt_join(_adapter *padapter); ++u8 rtw_ft_update_rsnie(_adapter *padapter, u8 bwrite, ++ struct pkt_attrib *pattrib, u8 **pframe); ++void rtw_ft_build_auth_req_ies(_adapter *padapter, ++ struct pkt_attrib *pattrib, u8 **pframe); ++void rtw_ft_build_assoc_req_ies(_adapter *padapter, ++ u8 is_reassoc, struct pkt_attrib *pattrib, u8 **pframe); ++u8 rtw_ft_update_auth_rsp_ies(_adapter *padapter, u8 *pframe, u32 len); ++void rtw_ft_start_roam(_adapter *padapter, u8 *pTargetAddr); ++void rtw_ft_issue_action_req(_adapter *padapter, u8 *pTargetAddr); ++void rtw_ft_report_evt(_adapter *padapter); ++void rtw_ft_report_reassoc_evt(_adapter *padapter, u8 *pMacAddr); ++void rtw_ft_link_timer_hdl(void *ctx); ++void rtw_ft_roam_timer_hdl(void *ctx); ++void rtw_ft_roam_status_reset(_adapter *padapter); ++#endif ++#ifdef CONFIG_RTW_WNM ++void rtw_wnm_roam_scan_hdl(void *ctx); ++void rtw_wnm_process_btm_req(_adapter *padapter, u8* pframe, u32 frame_len); ++void rtw_wnm_reset_btm_candidate(struct roam_nb_info *pnb); ++void rtw_wnm_reset_btm_state(_adapter *padapter); ++void rtw_wnm_issue_action(_adapter *padapter, u8 action, u8 reason); ++#endif ++#if defined(CONFIG_RTW_WNM) || defined(CONFIG_RTW_80211K) ++u32 rtw_wnm_btm_candidates_survey(_adapter *padapter, u8* pframe, u32 elem_len, u8 is_preference); ++#endif ++void mlmeext_joinbss_event_callback(_adapter *padapter, int join_res); ++void mlmeext_sta_del_event_callback(_adapter *padapter); ++void mlmeext_sta_add_event_callback(_adapter *padapter, struct sta_info *psta); ++ ++void linked_status_chk(_adapter *padapter, u8 from_timer); ++ ++#define rtw_get_bcn_cnt(adapter) (adapter->mlmeextpriv.cur_bcn_cnt) ++#define rtw_get_bcn_dtim_period(adapter) (adapter->mlmeextpriv.dtim) ++void rtw_collect_bcn_info(_adapter *adapter); ++ ++void _linked_info_dump(_adapter *padapter); ++ ++void survey_timer_hdl(void *ctx); ++#ifdef CONFIG_RTW_REPEATER_SON ++void rson_timer_hdl(void *ctx); ++#endif ++void link_timer_hdl(void *ctx); ++void addba_timer_hdl(void *ctx); ++#ifdef CONFIG_IEEE80211W ++void sa_query_timer_hdl(void *ctx); ++#endif /* CONFIG_IEEE80211W */ ++#if 0 ++void reauth_timer_hdl(_adapter *padapter); ++void reassoc_timer_hdl(_adapter *padapter); ++#endif ++ ++#define set_survey_timer(mlmeext, ms) \ ++ do { \ ++ /*RTW_INFO("%s set_survey_timer(%p, %d)\n", __FUNCTION__, (mlmeext), (ms));*/ \ ++ _set_timer(&(mlmeext)->survey_timer, (ms)); \ ++ } while (0) ++ ++#define set_link_timer(mlmeext, ms) \ ++ do { \ ++ /*RTW_INFO("%s set_link_timer(%p, %d)\n", __FUNCTION__, (mlmeext), (ms));*/ \ ++ _set_timer(&(mlmeext)->link_timer, (ms)); \ ++ } while (0) ++ ++bool rtw_is_basic_rate_cck(u8 rate); ++bool rtw_is_basic_rate_ofdm(u8 rate); ++bool rtw_is_basic_rate_mix(u8 rate); ++ ++extern int cckrates_included(unsigned char *rate, int ratelen); ++extern int cckratesonly_included(unsigned char *rate, int ratelen); ++ ++extern void process_addba_req(_adapter *padapter, u8 *paddba_req, u8 *addr); ++ ++extern void update_TSF(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len); ++extern void correct_TSF(_adapter *padapter, u8 mlme_state); ++#ifdef CONFIG_BCN_RECV_TIME ++void rtw_rx_bcn_time_update(_adapter *adapter, uint bcn_len, u8 data_rate); ++#endif ++extern u8 traffic_status_watchdog(_adapter *padapter, u8 from_timer); ++ ++void rtw_process_bar_frame(_adapter *padapter, union recv_frame *precv_frame); ++void rtw_join_done_chk_ch(_adapter *padapter, int join_res); ++ ++int rtw_chk_start_clnt_join(_adapter *padapter, u8 *ch, u8 *bw, u8 *offset); ++ ++#ifdef CONFIG_PLATFORM_ARM_SUN8I ++ #define BUSY_TRAFFIC_SCAN_DENY_PERIOD 8000 ++#else ++ #define BUSY_TRAFFIC_SCAN_DENY_PERIOD 12000 ++#endif ++ ++struct cmd_hdl { ++ uint parmsize; ++ u8(*h2cfuns)(struct _ADAPTER *padapter, u8 *pbuf); ++}; ++ ++void rtw_leave_opch(_adapter *adapter); ++void rtw_back_opch(_adapter *adapter); ++ ++u8 read_macreg_hdl(_adapter *padapter, u8 *pbuf); ++u8 write_macreg_hdl(_adapter *padapter, u8 *pbuf); ++u8 read_bbreg_hdl(_adapter *padapter, u8 *pbuf); ++u8 write_bbreg_hdl(_adapter *padapter, u8 *pbuf); ++u8 read_rfreg_hdl(_adapter *padapter, u8 *pbuf); ++u8 write_rfreg_hdl(_adapter *padapter, u8 *pbuf); ++ ++ ++u8 NULL_hdl(_adapter *padapter, u8 *pbuf); ++u8 join_cmd_hdl(_adapter *padapter, u8 *pbuf); ++u8 disconnect_hdl(_adapter *padapter, u8 *pbuf); ++u8 createbss_hdl(_adapter *padapter, u8 *pbuf); ++#ifdef CONFIG_AP_MODE ++u8 stop_ap_hdl(_adapter *adapter); ++#endif ++u8 setopmode_hdl(_adapter *padapter, u8 *pbuf); ++u8 sitesurvey_cmd_hdl(_adapter *padapter, u8 *pbuf); ++u8 setauth_hdl(_adapter *padapter, u8 *pbuf); ++u8 setkey_hdl(_adapter *padapter, u8 *pbuf); ++u8 set_stakey_hdl(_adapter *padapter, u8 *pbuf); ++u8 set_assocsta_hdl(_adapter *padapter, u8 *pbuf); ++u8 del_assocsta_hdl(_adapter *padapter, u8 *pbuf); ++u8 add_ba_hdl(_adapter *padapter, unsigned char *pbuf); ++u8 add_ba_rsp_hdl(_adapter *padapter, unsigned char *pbuf); ++ ++void rtw_ap_wep_pk_setting(_adapter *adapter, struct sta_info *psta); ++ ++u8 mlme_evt_hdl(_adapter *padapter, unsigned char *pbuf); ++u8 h2c_msg_hdl(_adapter *padapter, unsigned char *pbuf); ++u8 chk_bmc_sleepq_hdl(_adapter *padapter, unsigned char *pbuf); ++u8 tx_beacon_hdl(_adapter *padapter, unsigned char *pbuf); ++u8 rtw_set_chbw_hdl(_adapter *padapter, u8 *pbuf); ++u8 set_chplan_hdl(_adapter *padapter, unsigned char *pbuf); ++u8 led_blink_hdl(_adapter *padapter, unsigned char *pbuf); ++u8 set_csa_hdl(_adapter *padapter, unsigned char *pbuf); /* Kurt: Handling DFS channel switch announcement ie. */ ++u8 tdls_hdl(_adapter *padapter, unsigned char *pbuf); ++u8 run_in_thread_hdl(_adapter *padapter, u8 *pbuf); ++u8 rtw_getmacreg_hdl(_adapter *padapter, u8 *pbuf); ++ ++int rtw_sae_preprocess(_adapter *adapter, const u8 *buf, u32 len, u8 tx); ++ ++#define GEN_DRV_CMD_HANDLER(size, cmd) {size, &cmd ## _hdl}, ++#define GEN_MLME_EXT_HANDLER(size, cmd) {size, cmd}, ++ ++#ifdef _RTW_CMD_C_ ++ ++struct cmd_hdl wlancmds[] = { ++ GEN_DRV_CMD_HANDLER(sizeof(struct readMAC_parm), rtw_getmacreg) /*0*/ ++ GEN_DRV_CMD_HANDLER(0, NULL) ++ GEN_DRV_CMD_HANDLER(0, NULL) ++ GEN_DRV_CMD_HANDLER(0, NULL) ++ GEN_DRV_CMD_HANDLER(0, NULL) ++ GEN_DRV_CMD_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) /*10*/ ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(sizeof(struct joinbss_parm), join_cmd_hdl) /*14*/ ++ GEN_MLME_EXT_HANDLER(sizeof(struct disconnect_parm), disconnect_hdl) ++ GEN_MLME_EXT_HANDLER(sizeof(struct createbss_parm), createbss_hdl) ++ GEN_MLME_EXT_HANDLER(sizeof(struct setopmode_parm), setopmode_hdl) ++ GEN_MLME_EXT_HANDLER(sizeof(struct sitesurvey_parm), sitesurvey_cmd_hdl) /*18*/ ++ GEN_MLME_EXT_HANDLER(sizeof(struct setauth_parm), setauth_hdl) ++ GEN_MLME_EXT_HANDLER(sizeof(struct setkey_parm), setkey_hdl) /*20*/ ++ GEN_MLME_EXT_HANDLER(sizeof(struct set_stakey_parm), set_stakey_hdl) ++ GEN_MLME_EXT_HANDLER(sizeof(struct set_assocsta_parm), NULL) ++ GEN_MLME_EXT_HANDLER(sizeof(struct del_assocsta_parm), NULL) ++ GEN_MLME_EXT_HANDLER(sizeof(struct setstapwrstate_parm), NULL) ++ GEN_MLME_EXT_HANDLER(sizeof(struct setbasicrate_parm), NULL) ++ GEN_MLME_EXT_HANDLER(sizeof(struct getbasicrate_parm), NULL) ++ GEN_MLME_EXT_HANDLER(sizeof(struct setdatarate_parm), NULL) ++ GEN_MLME_EXT_HANDLER(sizeof(struct getdatarate_parm), NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) /*30*/ ++ GEN_MLME_EXT_HANDLER(sizeof(struct setphy_parm), NULL) ++ GEN_MLME_EXT_HANDLER(sizeof(struct getphy_parm), NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) /*40*/ ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(sizeof(struct addBaReq_parm), add_ba_hdl) ++ GEN_MLME_EXT_HANDLER(sizeof(struct set_ch_parm), rtw_set_chbw_hdl) /* 46 */ ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) /*50*/ ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(sizeof(struct Tx_Beacon_param), tx_beacon_hdl) /*55*/ ++ ++ GEN_MLME_EXT_HANDLER(0, mlme_evt_hdl) /*56*/ ++ GEN_MLME_EXT_HANDLER(0, rtw_drvextra_cmd_hdl) /*57*/ ++ ++ GEN_MLME_EXT_HANDLER(0, h2c_msg_hdl) /*58*/ ++ GEN_MLME_EXT_HANDLER(sizeof(struct SetChannelPlan_param), set_chplan_hdl) /*59*/ ++ GEN_MLME_EXT_HANDLER(sizeof(struct LedBlink_param), led_blink_hdl) /*60*/ ++ ++ GEN_MLME_EXT_HANDLER(0, set_csa_hdl) /*61*/ ++ GEN_MLME_EXT_HANDLER(sizeof(struct TDLSoption_param), tdls_hdl) /*62*/ ++ GEN_MLME_EXT_HANDLER(0, chk_bmc_sleepq_hdl) /*63*/ ++ GEN_MLME_EXT_HANDLER(sizeof(struct RunInThread_param), run_in_thread_hdl) /*64*/ ++ GEN_MLME_EXT_HANDLER(sizeof(struct addBaRsp_parm), add_ba_rsp_hdl) /* 65 */ ++ GEN_MLME_EXT_HANDLER(sizeof(struct rm_event), rm_post_event_hdl) /* 66 */ ++}; ++ ++#endif ++ ++struct C2HEvent_Header { ++ ++#ifdef CONFIG_LITTLE_ENDIAN ++ ++ unsigned int len:16; ++ unsigned int ID:8; ++ unsigned int seq:8; ++ ++#elif defined(CONFIG_BIG_ENDIAN) ++ ++ unsigned int seq:8; ++ unsigned int ID:8; ++ unsigned int len:16; ++ ++#else ++ ++# error "Must be LITTLE or BIG Endian" ++ ++#endif ++ ++ unsigned int rsvd; ++ ++}; ++ ++void rtw_dummy_event_callback(_adapter *adapter , u8 *pbuf); ++void rtw_fwdbg_event_callback(_adapter *adapter , u8 *pbuf); ++ ++enum rtw_c2h_event { ++ GEN_EVT_CODE(_Read_MACREG) = 0, /*0*/ ++ GEN_EVT_CODE(_Read_BBREG), ++ GEN_EVT_CODE(_Read_RFREG), ++ GEN_EVT_CODE(_Read_EEPROM), ++ GEN_EVT_CODE(_Read_EFUSE), ++ GEN_EVT_CODE(_Read_CAM), /*5*/ ++ GEN_EVT_CODE(_Get_BasicRate), ++ GEN_EVT_CODE(_Get_DataRate), ++ GEN_EVT_CODE(_Survey), /*8*/ ++ GEN_EVT_CODE(_SurveyDone), /*9*/ ++ ++ GEN_EVT_CODE(_JoinBss) , /*10*/ ++ GEN_EVT_CODE(_AddSTA), ++ GEN_EVT_CODE(_DelSTA), ++ GEN_EVT_CODE(_AtimDone) , ++ GEN_EVT_CODE(_TX_Report), ++ GEN_EVT_CODE(_CCX_Report), /*15*/ ++ GEN_EVT_CODE(_DTM_Report), ++ GEN_EVT_CODE(_TX_Rate_Statistics), ++ GEN_EVT_CODE(_C2HLBK), ++ GEN_EVT_CODE(_FWDBG), ++ GEN_EVT_CODE(_C2HFEEDBACK), /*20*/ ++ GEN_EVT_CODE(_ADDBA), ++ GEN_EVT_CODE(_C2HBCN), ++ GEN_EVT_CODE(_ReportPwrState), /* filen: only for PCIE, USB */ ++ GEN_EVT_CODE(_CloseRF), /* filen: only for PCIE, work around ASPM */ ++ GEN_EVT_CODE(_WMM), /*25*/ ++#ifdef CONFIG_IEEE80211W ++ GEN_EVT_CODE(_TimeoutSTA), ++#endif /* CONFIG_IEEE80211W */ ++#ifdef CONFIG_RTW_80211R ++ GEN_EVT_CODE(_FT_REASSOC), ++#endif ++ MAX_C2HEVT ++}; ++ ++ ++#ifdef _RTW_MLME_EXT_C_ ++ ++static struct fwevent wlanevents[] = { ++ {0, rtw_dummy_event_callback}, /*0*/ ++ {0, NULL}, ++ {0, NULL}, ++ {0, NULL}, ++ {0, NULL}, ++ {0, NULL}, ++ {0, NULL}, ++ {0, NULL}, ++ {0, &rtw_survey_event_callback}, /*8*/ ++ {sizeof(struct surveydone_event), &rtw_surveydone_event_callback}, /*9*/ ++ ++ {0, &rtw_joinbss_event_callback}, /*10*/ ++ {sizeof(struct stassoc_event), &rtw_stassoc_event_callback}, ++ {sizeof(struct stadel_event), &rtw_stadel_event_callback}, ++ {0, &rtw_atimdone_event_callback}, ++ {0, rtw_dummy_event_callback}, ++ {0, NULL}, /*15*/ ++ {0, NULL}, ++ {0, NULL}, ++ {0, NULL}, ++ {0, rtw_fwdbg_event_callback}, ++ {0, NULL}, /*20*/ ++ {0, NULL}, ++ {0, NULL}, ++ {0, &rtw_cpwm_event_callback}, ++ {0, NULL}, ++ {0, &rtw_wmm_event_callback}, /*25*/ ++#ifdef CONFIG_IEEE80211W ++ {sizeof(struct stadel_event), &rtw_sta_timeout_event_callback}, ++#endif /* CONFIG_IEEE80211W */ ++#ifdef CONFIG_RTW_80211R ++ {sizeof(struct stassoc_event), &rtw_ft_reassoc_event_callback}, ++#endif ++}; ++ ++#endif/* _RTW_MLME_EXT_C_ */ ++ ++#endif +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_mlme.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_mlme.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_mlme.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_mlme.h 2021-03-07 18:16:17.090957755 +0200 @@ -0,0 +1,1427 @@ +/****************************************************************************** + * @@ -403076,1328 +400799,9 @@ index 000000000..cdac712cd +#define GET_TCP_CWR(_tcphdr) BE_BITS_TO_1BYTE(((u8 *)(_tcphdr)) + 13, 7, 1) + +#endif /* __RTL871X_MLME_H_ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_mlme_ext.h linux-5.8/3rdparty/rtl8812au/include/rtw_mlme_ext.h -new file mode 100644 -index 000000000..49fcaa9d7 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_mlme_ext.h -@@ -0,0 +1,1311 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+#ifndef __RTW_MLME_EXT_H_ -+#define __RTW_MLME_EXT_H_ -+ -+ -+/* Commented by Albert 20101105 -+ * Increase the SURVEY_TO value from 100 to 150 ( 100ms to 150ms ) -+ * The Realtek 8188CE SoftAP will spend around 100ms to send the probe response after receiving the probe request. -+ * So, this driver tried to extend the dwell time for each scanning channel. -+ * This will increase the chance to receive the probe response from SoftAP. */ -+#define SURVEY_TO (100) -+ -+#define REAUTH_TO (300) /* (50) */ -+#define REASSOC_TO (300) /* (50) */ -+/* #define DISCONNECT_TO (3000) */ -+#define ADDBA_TO (2000) -+ -+#define LINKED_TO (1) /* unit:2 sec, 1x2 = 2 sec */ -+ -+#define REAUTH_LIMIT (4) -+#define REASSOC_LIMIT (4) -+#define READDBA_LIMIT (2) -+ -+#ifdef CONFIG_GSPI_HCI -+ #define ROAMING_LIMIT 5 -+#else -+ #define ROAMING_LIMIT 8 -+#endif -+/* #define IOCMD_REG0 0x10250370 */ -+/* #define IOCMD_REG1 0x10250374 */ -+/* #define IOCMD_REG2 0x10250378 */ -+ -+/* #define FW_DYNAMIC_FUN_SWITCH 0x10250364 */ -+ -+/* #define WRITE_BB_CMD 0xF0000001 */ -+/* #define SET_CHANNEL_CMD 0xF3000000 */ -+/* #define UPDATE_RA_CMD 0xFD0000A2 */ -+ -+#define _HW_STATE_NOLINK_ 0x00 -+#define _HW_STATE_ADHOC_ 0x01 -+#define _HW_STATE_STATION_ 0x02 -+#define _HW_STATE_AP_ 0x03 -+#define _HW_STATE_MONITOR_ 0x04 -+ -+ -+#define _1M_RATE_ 0 -+#define _2M_RATE_ 1 -+#define _5M_RATE_ 2 -+#define _11M_RATE_ 3 -+#define _6M_RATE_ 4 -+#define _9M_RATE_ 5 -+#define _12M_RATE_ 6 -+#define _18M_RATE_ 7 -+#define _24M_RATE_ 8 -+#define _36M_RATE_ 9 -+#define _48M_RATE_ 10 -+#define _54M_RATE_ 11 -+ -+/******************************************************** -+MCS rate definitions -+*********************************************************/ -+#define MCS_RATE_1R (0x000000ff) -+#define MCS_RATE_2R (0x0000ffff) -+#define MCS_RATE_3R (0x00ffffff) -+#define MCS_RATE_4R (0xffffffff) -+#define MCS_RATE_2R_13TO15_OFF (0x00001fff) -+ -+ -+extern unsigned char RTW_WPA_OUI[]; -+extern unsigned char WMM_OUI[]; -+extern unsigned char WPS_OUI[]; -+extern unsigned char WFD_OUI[]; -+extern unsigned char P2P_OUI[]; -+ -+extern unsigned char WMM_INFO_OUI[]; -+extern unsigned char WMM_PARA_OUI[]; -+ -+typedef struct _RT_CHANNEL_PLAN { -+ unsigned char Channel[MAX_CHANNEL_NUM]; -+ unsigned char Len; -+} RT_CHANNEL_PLAN, *PRT_CHANNEL_PLAN; -+ -+enum Associated_AP { -+ atherosAP = 0, -+ broadcomAP = 1, -+ ciscoAP = 2, -+ marvellAP = 3, -+ ralinkAP = 4, -+ realtekAP = 5, -+ airgocapAP = 6, -+ unknownAP = 7, -+ maxAP, -+}; -+ -+typedef enum _HT_IOT_PEER { -+ HT_IOT_PEER_UNKNOWN = 0, -+ HT_IOT_PEER_REALTEK = 1, -+ HT_IOT_PEER_REALTEK_92SE = 2, -+ HT_IOT_PEER_BROADCOM = 3, -+ HT_IOT_PEER_RALINK = 4, -+ HT_IOT_PEER_ATHEROS = 5, -+ HT_IOT_PEER_CISCO = 6, -+ HT_IOT_PEER_MERU = 7, -+ HT_IOT_PEER_MARVELL = 8, -+ HT_IOT_PEER_REALTEK_SOFTAP = 9,/* peer is RealTek SOFT_AP, by Bohn, 2009.12.17 */ -+ HT_IOT_PEER_SELF_SOFTAP = 10, /* Self is SoftAP */ -+ HT_IOT_PEER_AIRGO = 11, -+ HT_IOT_PEER_INTEL = 12, -+ HT_IOT_PEER_RTK_APCLIENT = 13, -+ HT_IOT_PEER_REALTEK_81XX = 14, -+ HT_IOT_PEER_REALTEK_WOW = 15, -+ HT_IOT_PEER_REALTEK_JAGUAR_BCUTAP = 16, -+ HT_IOT_PEER_REALTEK_JAGUAR_CCUTAP = 17, -+ HT_IOT_PEER_MAX = 18 -+} HT_IOT_PEER_E, *PHTIOT_PEER_E; -+ -+ -+typedef enum _RT_HT_INF0_CAP { -+ RT_HT_CAP_USE_TURBO_AGGR = 0x01, -+ RT_HT_CAP_USE_LONG_PREAMBLE = 0x02, -+ RT_HT_CAP_USE_AMPDU = 0x04, -+ RT_HT_CAP_USE_WOW = 0x8, -+ RT_HT_CAP_USE_SOFTAP = 0x10, -+ RT_HT_CAP_USE_92SE = 0x20, -+ RT_HT_CAP_USE_88C_92C = 0x40, -+ RT_HT_CAP_USE_AP_CLIENT_MODE = 0x80, /* AP team request to reserve this bit, by Emily */ -+} RT_HT_INF0_CAPBILITY, *PRT_HT_INF0_CAPBILITY; -+ -+typedef enum _RT_HT_INF1_CAP { -+ RT_HT_CAP_USE_VIDEO_CLIENT = 0x01, -+ RT_HT_CAP_USE_JAGUAR_BCUT = 0x02, -+ RT_HT_CAP_USE_JAGUAR_CCUT = 0x04, -+} RT_HT_INF1_CAPBILITY, *PRT_HT_INF1_CAPBILITY; -+ -+struct mlme_handler { -+ unsigned int num; -+ char *str; -+ unsigned int (*func)(_adapter *padapter, union recv_frame *precv_frame); -+}; -+ -+struct action_handler { -+ unsigned int num; -+ char *str; -+ unsigned int (*func)(_adapter *padapter, union recv_frame *precv_frame); -+}; -+ -+enum SCAN_STATE { -+ SCAN_DISABLE = 0, -+ SCAN_START = 1, -+ SCAN_PS_ANNC_WAIT = 2, -+ SCAN_ENTER = 3, -+ SCAN_PROCESS = 4, -+ -+ /* backop */ -+ SCAN_BACKING_OP = 5, -+ SCAN_BACK_OP = 6, -+ SCAN_LEAVING_OP = 7, -+ SCAN_LEAVE_OP = 8, -+ -+ /* SW antenna diversity (before linked) */ -+ SCAN_SW_ANTDIV_BL = 9, -+ -+ /* legacy p2p */ -+ SCAN_TO_P2P_LISTEN = 10, -+ SCAN_P2P_LISTEN = 11, -+ -+ SCAN_COMPLETE = 12, -+ SCAN_STATE_MAX, -+}; -+ -+const char *scan_state_str(u8 state); -+ -+enum ss_backop_flag { -+ SS_BACKOP_EN = BIT0, /* backop when linked */ -+ SS_BACKOP_EN_NL = BIT1, /* backop even when no linked */ -+ -+ SS_BACKOP_PS_ANNC = BIT4, -+ SS_BACKOP_TX_RESUME = BIT5, -+}; -+ -+struct ss_res { -+ u8 state; -+ u8 next_state; /* will set to state on next cmd hdl */ -+ int bss_cnt; -+ int channel_idx; -+#ifdef CONFIG_DFS -+ u8 dfs_ch_ssid_scan; -+#endif -+ int scan_mode; -+ u16 scan_ch_ms; -+ u32 scan_timeout_ms; -+ u8 rx_ampdu_accept; -+ u8 rx_ampdu_size; -+ u8 igi_scan; -+ u8 igi_before_scan; /* used for restoring IGI value without enable DIG & FA_CNT */ -+#ifdef CONFIG_SCAN_BACKOP -+ u8 backop_flags_sta; /* policy for station mode*/ -+ #ifdef CONFIG_AP_MODE -+ u8 backop_flags_ap; /* policy for ap mode */ -+ #endif -+ #ifdef CONFIG_RTW_MESH -+ u8 backop_flags_mesh; /* policy for mesh mode */ -+ #endif -+ u8 backop_flags; /* per backop runtime decision */ -+ u8 scan_cnt; -+ u8 scan_cnt_max; -+ systime backop_time; /* the start time of backop */ -+ u16 backop_ms; -+#endif -+#if defined(CONFIG_ANTENNA_DIVERSITY) || defined(DBG_SCAN_SW_ANTDIV_BL) -+ u8 is_sw_antdiv_bl_scan; -+#endif -+ u8 ssid_num; -+ u8 ch_num; -+ NDIS_802_11_SSID ssid[RTW_SSID_SCAN_AMOUNT]; -+ struct rtw_ieee80211_channel ch[RTW_CHANNEL_SCAN_AMOUNT]; -+ -+ u32 token; /* 0: use to identify caller */ -+ u16 duration; /* 0: use default */ -+ u8 igi; /* 0: use defalut */ -+ u8 bw; /* 0: use default */ -+}; -+ -+/* #define AP_MODE 0x0C */ -+/* #define STATION_MODE 0x08 */ -+/* #define AD_HOC_MODE 0x04 */ -+/* #define NO_LINK_MODE 0x00 */ -+ -+#define WIFI_FW_NULL_STATE _HW_STATE_NOLINK_ -+#define WIFI_FW_STATION_STATE _HW_STATE_STATION_ -+#define WIFI_FW_AP_STATE _HW_STATE_AP_ -+#define WIFI_FW_ADHOC_STATE _HW_STATE_ADHOC_ -+ -+#define WIFI_FW_PRE_LINK 0x00000800 -+#define WIFI_FW_AUTH_NULL 0x00000100 -+#define WIFI_FW_AUTH_STATE 0x00000200 -+#define WIFI_FW_AUTH_SUCCESS 0x00000400 -+ -+#define WIFI_FW_ASSOC_STATE 0x00002000 -+#define WIFI_FW_ASSOC_SUCCESS 0x00004000 -+ -+#define WIFI_FW_LINKING_STATE (WIFI_FW_AUTH_NULL | WIFI_FW_AUTH_STATE | WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE) -+ -+#ifdef CONFIG_TDLS -+enum TDLS_option { -+ TDLS_ESTABLISHED = 1, -+ TDLS_ISSUE_PTI, -+ TDLS_CH_SW_RESP, -+ TDLS_CH_SW_PREPARE, -+ TDLS_CH_SW_START, -+ TDLS_CH_SW_TO_OFF_CHNL, -+ TDLS_CH_SW_TO_BASE_CHNL_UNSOLICITED, -+ TDLS_CH_SW_TO_BASE_CHNL, -+ TDLS_CH_SW_END_TO_BASE_CHNL, -+ TDLS_CH_SW_END, -+ TDLS_RS_RCR, -+ TDLS_TEARDOWN_STA, -+ TDLS_TEARDOWN_STA_NO_WAIT, -+ TDLS_TEARDOWN_STA_LOCALLY, -+ TDLS_TEARDOWN_STA_LOCALLY_POST, -+ maxTDLS, -+}; -+ -+#endif /* CONFIG_TDLS */ -+ -+#ifndef NL80211_AUTHTYPE_SAE -+#define NL80211_AUTHTYPE_SAE 4 -+#endif -+ -+/* -+ * Usage: -+ * When one iface acted as AP mode and the other iface is STA mode and scanning, -+ * it should switch back to AP's operating channel periodically. -+ * Parameters info: -+ * When the driver scanned RTW_SCAN_NUM_OF_CH channels, it would switch back to AP's operating channel for -+ * RTW_BACK_OP_CH_MS milliseconds. -+ * Example: -+ * For chip supports 2.4G + 5GHz and AP mode is operating in channel 1, -+ * RTW_SCAN_NUM_OF_CH is 8, RTW_BACK_OP_CH_MS is 300 -+ * When it's STA mode gets set_scan command, -+ * it would -+ * 1. Doing the scan on channel 1.2.3.4.5.6.7.8 -+ * 2. Back to channel 1 for 300 milliseconds -+ * 3. Go through doing site survey on channel 9.10.11.36.40.44.48.52 -+ * 4. Back to channel 1 for 300 milliseconds -+ * 5. ... and so on, till survey done. -+ */ -+#if defined(CONFIG_ATMEL_RC_PATCH) -+ #define RTW_SCAN_NUM_OF_CH 2 -+ #define RTW_BACK_OP_CH_MS 200 -+#else -+ #define RTW_SCAN_NUM_OF_CH 3 -+ #define RTW_BACK_OP_CH_MS 400 -+#endif -+ -+#define RTW_IP_ADDR_LEN 4 -+#define RTW_IPv6_ADDR_LEN 16 -+ -+struct mlme_ext_info { -+ u32 state; -+#ifdef CONFIG_MI_WITH_MBSSID_CAM -+ u8 hw_media_state; -+#endif -+ u32 reauth_count; -+ u32 reassoc_count; -+ u32 link_count; -+ u32 auth_seq; -+ u32 auth_algo; /* 802.11 auth, could be open, shared, auto */ -+ u16 auth_status; -+ u32 authModeToggle; -+ u32 enc_algo;/* encrypt algorithm; */ -+ u32 key_index; /* this is only valid for legendary wep, 0~3 for key id. */ -+ u32 iv; -+ u8 chg_txt[128]; -+ u16 aid; -+ u16 bcn_interval; -+ u16 capability; -+ u8 assoc_AP_vendor; -+ u8 slotTime; -+ u8 preamble_mode; -+ u8 WMM_enable; -+ u8 ERP_enable; -+ u8 ERP_IE; -+ u8 HT_enable; -+ u8 HT_caps_enable; -+ u8 HT_info_enable; -+ u8 HT_protection; -+ u8 turboMode_cts2self; -+ u8 turboMode_rtsen; -+ u8 SM_PS; -+ u8 agg_enable_bitmap; -+ u8 ADDBA_retry_count; -+ u8 candidate_tid_bitmap; -+ u8 dialogToken; -+ /* Accept ADDBA Request */ -+ BOOLEAN bAcceptAddbaReq; -+ u8 bwmode_updated; -+ u8 hidden_ssid_mode; -+ u8 VHT_enable; -+ -+ u8 ip_addr[RTW_IP_ADDR_LEN]; -+ u8 ip6_addr[RTW_IPv6_ADDR_LEN]; -+ -+ struct ADDBA_request ADDBA_req; -+ struct WMM_para_element WMM_param; -+ struct HT_caps_element HT_caps; -+ struct HT_info_element HT_info; -+ WLAN_BSSID_EX network;/* join network or bss_network, if in ap mode, it is the same to cur_network.network */ -+#ifdef ROKU_PRIVATE -+ /*infra mode, store supported rates from AssocRsp*/ -+ NDIS_802_11_RATES_EX SupportedRates_infra_ap; -+ u8 ht_vht_received;/*ht_vht_received used to show debug msg BIT(0):HT BIT(1):VHT */ -+#endif /* ROKU_PRIVATE */ -+}; -+ -+/* The channel information about this channel including joining, scanning, and power constraints. */ -+typedef struct _RT_CHANNEL_INFO { -+ u8 ChannelNum; /* The channel number. */ -+ RT_SCAN_TYPE ScanType; /* Scan type such as passive or active scan. */ -+ /* u16 ScanPeriod; */ /* Listen time in millisecond in this channel. */ -+ /* s32 MaxTxPwrDbm; */ /* Max allowed tx power. */ -+ /* u32 ExInfo; */ /* Extended Information for this channel. */ -+#ifdef CONFIG_FIND_BEST_CHANNEL -+ u32 rx_count; -+#endif -+#ifdef CONFIG_DFS -+ #ifdef CONFIG_DFS_MASTER -+ systime non_ocp_end_time; -+ #endif -+ u8 hidden_bss_cnt; /* per scan count */ -+#endif -+} RT_CHANNEL_INFO, *PRT_CHANNEL_INFO; -+ -+#define CAC_TIME_MS (60*1000) -+#define CAC_TIME_CE_MS (10*60*1000) -+#define NON_OCP_TIME_MS (30*60*1000) -+ -+#if CONFIG_TXPWR_LIMIT -+void rtw_txpwr_init_regd(struct rf_ctl_t *rfctl); -+#endif -+void rtw_rfctl_init(_adapter *adapter); -+void rtw_rfctl_deinit(_adapter *adapter); -+ -+#ifdef CONFIG_DFS_MASTER -+struct rf_ctl_t; -+#define CH_IS_NON_OCP(rt_ch_info) (rtw_time_after((rt_ch_info)->non_ocp_end_time, rtw_get_current_time())) -+bool rtw_is_cac_reset_needed(struct rf_ctl_t *rfctl, u8 ch, u8 bw, u8 offset); -+bool _rtw_rfctl_overlap_radar_detect_ch(struct rf_ctl_t *rfctl, u8 ch, u8 bw, u8 offset); -+bool rtw_rfctl_overlap_radar_detect_ch(struct rf_ctl_t *rfctl); -+bool rtw_rfctl_is_tx_blocked_by_ch_waiting(struct rf_ctl_t *rfctl); -+bool rtw_chset_is_chbw_non_ocp(RT_CHANNEL_INFO *ch_set, u8 ch, u8 bw, u8 offset); -+bool rtw_chset_is_ch_non_ocp(RT_CHANNEL_INFO *ch_set, u8 ch); -+void rtw_chset_update_non_ocp(RT_CHANNEL_INFO *ch_set, u8 ch, u8 bw, u8 offset); -+void rtw_chset_update_non_ocp_ms(RT_CHANNEL_INFO *ch_set, u8 ch, u8 bw, u8 offset, int ms); -+u32 rtw_get_ch_waiting_ms(struct rf_ctl_t *rfctl, u8 ch, u8 bw, u8 offset, u32 *r_non_ocp_ms, u32 *r_cac_ms); -+void rtw_reset_cac(struct rf_ctl_t *rfctl, u8 ch, u8 bw, u8 offset); -+u32 rtw_force_stop_cac(struct rf_ctl_t *rfctl, u32 timeout_ms); -+#else -+#define CH_IS_NON_OCP(rt_ch_info) 0 -+#define rtw_chset_is_chbw_non_ocp(ch_set, ch, bw, offset) _FALSE -+#define rtw_chset_is_ch_non_ocp(ch_set, ch) _FALSE -+#define rtw_rfctl_is_tx_blocked_by_ch_waiting(rfctl) _FALSE -+#endif -+ -+enum { -+ RTW_CHF_2G = BIT0, -+ RTW_CHF_5G = BIT1, -+ RTW_CHF_DFS = BIT2, -+ RTW_CHF_LONG_CAC = BIT3, -+ RTW_CHF_NON_DFS = BIT4, -+ RTW_CHF_NON_LONG_CAC = BIT5, -+ RTW_CHF_NON_OCP = BIT6, -+}; -+ -+bool rtw_choose_shortest_waiting_ch(struct rf_ctl_t *rfctl, u8 sel_ch, u8 max_bw -+ , u8 *dec_ch, u8 *dec_bw, u8 *dec_offset -+ , u8 d_flags, u8 cur_ch, u8 same_band_prefer, u8 mesh_only); -+ -+void dump_chset(void *sel, RT_CHANNEL_INFO *ch_set); -+void dump_cur_chset(void *sel, struct rf_ctl_t *rfctl); -+ -+int rtw_chset_search_ch(RT_CHANNEL_INFO *ch_set, const u32 ch); -+u8 rtw_chset_is_chbw_valid(RT_CHANNEL_INFO *ch_set, u8 ch, u8 bw, u8 offset); -+void rtw_chset_sync_chbw(RT_CHANNEL_INFO *ch_set, u8 *req_ch, u8 *req_bw, u8 *req_offset -+ , u8 *g_ch, u8 *g_bw, u8 *g_offset); -+ -+bool rtw_mlme_band_check(_adapter *adapter, const u32 ch); -+ -+ -+enum { -+ BAND_24G = BIT0, -+ BAND_5G = BIT1, -+}; -+void RTW_SET_SCAN_BAND_SKIP(_adapter *padapter, int skip_band); -+void RTW_CLR_SCAN_BAND_SKIP(_adapter *padapter, int skip_band); -+int RTW_GET_SCAN_BAND_SKIP(_adapter *padapter); -+ -+bool rtw_mlme_ignore_chan(_adapter *adapter, const u32 ch); -+ -+/* P2P_MAX_REG_CLASSES - Maximum number of regulatory classes */ -+#define P2P_MAX_REG_CLASSES 10 -+ -+/* P2P_MAX_REG_CLASS_CHANNELS - Maximum number of channels per regulatory class */ -+#define P2P_MAX_REG_CLASS_CHANNELS 20 -+ -+/* struct p2p_channels - List of supported channels */ -+struct p2p_channels { -+ /* struct p2p_reg_class - Supported regulatory class */ -+ struct p2p_reg_class { -+ /* reg_class - Regulatory class (IEEE 802.11-2007, Annex J) */ -+ u8 reg_class; -+ -+ /* channel - Supported channels */ -+ u8 channel[P2P_MAX_REG_CLASS_CHANNELS]; -+ -+ /* channels - Number of channel entries in use */ -+ size_t channels; -+ } reg_class[P2P_MAX_REG_CLASSES]; -+ -+ /* reg_classes - Number of reg_class entries in use */ -+ size_t reg_classes; -+}; -+ -+struct p2p_oper_class_map { -+ enum hw_mode {IEEE80211G, IEEE80211A} mode; -+ u8 op_class; -+ u8 min_chan; -+ u8 max_chan; -+ u8 inc; -+ enum { BW20, BW40PLUS, BW40MINUS } bw; -+}; -+ -+struct mlme_ext_priv { -+ _adapter *padapter; -+ u8 mlmeext_init; -+ ATOMIC_T event_seq; -+ u16 mgnt_seq; -+#ifdef CONFIG_IEEE80211W -+ u16 sa_query_seq; -+#endif -+ /* struct fw_priv fwpriv; */ -+ -+ unsigned char cur_channel; -+ unsigned char cur_bwmode; -+ unsigned char cur_ch_offset;/* PRIME_CHNL_OFFSET */ -+ unsigned char cur_wireless_mode; /* NETWORK_TYPE */ -+ -+ unsigned char basicrate[NumRates]; -+ unsigned char datarate[NumRates]; -+#ifdef CONFIG_80211N_HT -+ unsigned char default_supported_mcs_set[16]; -+#endif -+ -+ struct ss_res sitesurvey_res; -+ struct mlme_ext_info mlmext_info;/* for sta/adhoc mode, including current scanning/connecting/connected related info. -+ * for ap mode, network includes ap's cap_info */ -+ _timer survey_timer; -+ _timer link_timer; -+ -+#ifdef CONFIG_RTW_REPEATER_SON -+ _timer rson_scan_timer; -+#endif -+#ifdef CONFIG_RTW_80211R -+ _timer ft_link_timer; -+ _timer ft_roam_timer; -+#endif -+ -+ systime last_scan_time; -+ u8 scan_abort; -+ u8 join_abort; -+ u8 tx_rate; /* TXRATE when USERATE is set. */ -+ -+ u32 retry; /* retry for issue probereq */ -+ -+ u64 TSFValue; -+ u32 bcn_cnt; -+ u32 last_bcn_cnt; -+ u8 cur_bcn_cnt;/*2s*/ -+ u8 dtim;/*DTIM Period*/ -+#ifdef DBG_RX_BCN -+ u8 tim[4]; -+#endif -+#ifdef CONFIG_BCN_RECV_TIME -+ u16 bcn_rx_time; -+#endif -+#ifdef CONFIG_AP_MODE -+ unsigned char bstart_bss; -+#endif -+ -+#ifdef CONFIG_80211D -+ u8 update_channel_plan_by_ap_done; -+#endif -+ /* recv_decache check for Action_public frame */ -+ u8 action_public_dialog_token; -+ u16 action_public_rxseq; -+ -+ /* #ifdef CONFIG_ACTIVE_KEEP_ALIVE_CHECK */ -+ u8 active_keep_alive_check; -+ /* #endif */ -+#ifdef DBG_FIXED_CHAN -+ u8 fixed_chan; -+#endif -+ -+ u8 tsf_update_required:1; -+ u8 en_hw_update_tsf:1; /* set hw sync bcn tsf register or not */ -+ systime tsf_update_pause_stime; -+ u8 tsf_update_pause_factor; /* num of bcn intervals to stay TSF update pause status */ -+ u8 tsf_update_restore_factor; /* num of bcn interval to stay TSF update restore status */ -+#ifdef CONFIG_SUPPORT_STATIC_SMPS -+ u8 ssmps_en; -+ u16 ssmps_tx_tp_th;/*Mbps*/ -+ u16 ssmps_rx_tp_th;/*Mbps*/ -+ #ifdef DBG_STATIC_SMPS -+ u8 ssmps_test; -+ u8 ssmps_test_en; -+ #endif -+#endif -+#ifdef CONFIG_CTRL_TXSS_BY_TP -+ u8 txss_ctrl_en; -+ u16 txss_tp_th;/*Mbps*/ -+ u8 txss_tp_chk_cnt;/*unit 2s*/ -+ u8 txss_1ss; -+ u8 txss_momi_type_bk; -+#endif -+}; -+ -+struct support_rate_handler { -+ u8 rate; -+ bool basic; -+ bool existence; -+}; -+ -+static inline u8 check_mlmeinfo_state(struct mlme_ext_priv *plmeext, sint state) -+{ -+ if ((plmeext->mlmext_info.state & 0x03) == state) -+ return _TRUE; -+ -+ return _FALSE; -+} -+ -+void sitesurvey_set_offch_state(_adapter *adapter, u8 scan_state); -+ -+#define mlmeext_msr(mlmeext) ((mlmeext)->mlmext_info.state & 0x03) -+#define mlmeext_scan_state(mlmeext) ((mlmeext)->sitesurvey_res.state) -+#define mlmeext_scan_state_str(mlmeext) scan_state_str((mlmeext)->sitesurvey_res.state) -+#define mlmeext_chk_scan_state(mlmeext, _state) ((mlmeext)->sitesurvey_res.state == (_state)) -+#define mlmeext_set_scan_state(mlmeext, _state) \ -+ do { \ -+ ((mlmeext)->sitesurvey_res.state = (_state)); \ -+ ((mlmeext)->sitesurvey_res.next_state = (_state)); \ -+ rtw_mi_update_iface_status(&((container_of(mlmeext, _adapter, mlmeextpriv)->mlmepriv)), 0); \ -+ /* RTW_INFO("set_scan_state:%s\n", scan_state_str(_state)); */ \ -+ sitesurvey_set_offch_state(container_of(mlmeext, _adapter, mlmeextpriv), _state); \ -+ } while (0) -+ -+#define mlmeext_scan_next_state(mlmeext) ((mlmeext)->sitesurvey_res.next_state) -+#define mlmeext_set_scan_next_state(mlmeext, _state) \ -+ do { \ -+ ((mlmeext)->sitesurvey_res.next_state = (_state)); \ -+ /* RTW_INFO("set_scan_next_state:%s\n", scan_state_str(_state)); */ \ -+ } while (0) -+ -+#ifdef CONFIG_SCAN_BACKOP -+#define mlmeext_scan_backop_flags(mlmeext) ((mlmeext)->sitesurvey_res.backop_flags) -+#define mlmeext_chk_scan_backop_flags(mlmeext, flags) ((mlmeext)->sitesurvey_res.backop_flags & (flags)) -+#define mlmeext_assign_scan_backop_flags(mlmeext, flags) \ -+ do { \ -+ ((mlmeext)->sitesurvey_res.backop_flags = (flags)); \ -+ RTW_INFO("assign_scan_backop_flags:0x%02x\n", (mlmeext)->sitesurvey_res.backop_flags); \ -+ } while (0) -+ -+#define mlmeext_scan_backop_flags_sta(mlmeext) ((mlmeext)->sitesurvey_res.backop_flags_sta) -+#define mlmeext_chk_scan_backop_flags_sta(mlmeext, flags) ((mlmeext)->sitesurvey_res.backop_flags_sta & (flags)) -+#define mlmeext_assign_scan_backop_flags_sta(mlmeext, flags) \ -+ do { \ -+ ((mlmeext)->sitesurvey_res.backop_flags_sta = (flags)); \ -+ } while (0) -+#else -+#define mlmeext_scan_backop_flags(mlmeext) (0) -+#define mlmeext_chk_scan_backop_flags(mlmeext, flags) (0) -+#define mlmeext_assign_scan_backop_flags(mlmeext, flags) do {} while (0) -+ -+#define mlmeext_scan_backop_flags_sta(mlmeext) (0) -+#define mlmeext_chk_scan_backop_flags_sta(mlmeext, flags) (0) -+#define mlmeext_assign_scan_backop_flags_sta(mlmeext, flags) do {} while (0) -+#endif /* CONFIG_SCAN_BACKOP */ -+ -+#if defined(CONFIG_SCAN_BACKOP) && defined(CONFIG_AP_MODE) -+#define mlmeext_scan_backop_flags_ap(mlmeext) ((mlmeext)->sitesurvey_res.backop_flags_ap) -+#define mlmeext_chk_scan_backop_flags_ap(mlmeext, flags) ((mlmeext)->sitesurvey_res.backop_flags_ap & (flags)) -+#define mlmeext_assign_scan_backop_flags_ap(mlmeext, flags) \ -+ do { \ -+ ((mlmeext)->sitesurvey_res.backop_flags_ap = (flags)); \ -+ } while (0) -+#else -+#define mlmeext_scan_backop_flags_ap(mlmeext) (0) -+#define mlmeext_chk_scan_backop_flags_ap(mlmeext, flags) (0) -+#define mlmeext_assign_scan_backop_flags_ap(mlmeext, flags) do {} while (0) -+#endif /* defined(CONFIG_SCAN_BACKOP) && defined(CONFIG_AP_MODE) */ -+ -+#if defined(CONFIG_SCAN_BACKOP) && defined(CONFIG_RTW_MESH) -+#define mlmeext_scan_backop_flags_mesh(mlmeext) ((mlmeext)->sitesurvey_res.backop_flags_mesh) -+#define mlmeext_chk_scan_backop_flags_mesh(mlmeext, flags) ((mlmeext)->sitesurvey_res.backop_flags_mesh & (flags)) -+#define mlmeext_assign_scan_backop_flags_mesh(mlmeext, flags) \ -+ do { \ -+ ((mlmeext)->sitesurvey_res.backop_flags_mesh = (flags)); \ -+ } while (0) -+#else -+#define mlmeext_scan_backop_flags_mesh(mlmeext) (0) -+#define mlmeext_chk_scan_backop_flags_mesh(mlmeext, flags) (0) -+#define mlmeext_assign_scan_backop_flags_mesh(mlmeext, flags) do {} while (0) -+#endif /* defined(CONFIG_SCAN_BACKOP) && defined(CONFIG_RTW_MESH) */ -+ -+u32 rtw_scan_timeout_decision(_adapter *padapter); -+ -+void init_mlme_default_rate_set(_adapter *padapter); -+int init_mlme_ext_priv(_adapter *padapter); -+int init_hw_mlme_ext(_adapter *padapter); -+void free_mlme_ext_priv(struct mlme_ext_priv *pmlmeext); -+extern struct xmit_frame *alloc_mgtxmitframe(struct xmit_priv *pxmitpriv); -+struct xmit_frame *alloc_mgtxmitframe_once(struct xmit_priv *pxmitpriv); -+ -+/* void fill_fwpriv(_adapter * padapter, struct fw_priv *pfwpriv); */ -+u8 judge_network_type(_adapter *padapter, unsigned char *rate, int ratelen); -+void get_rate_set(_adapter *padapter, unsigned char *pbssrate, int *bssrate_len); -+void set_mcs_rate_by_mask(u8 *mcs_set, u32 mask); -+void UpdateBrateTbl(_adapter *padapter, u8 *mBratesOS); -+void UpdateBrateTblForSoftAP(u8 *bssrateset, u32 bssratelen); -+void change_band_update_ie(_adapter *padapter, WLAN_BSSID_EX *pnetwork, u8 ch); -+ -+void Set_MSR(_adapter *padapter, u8 type); -+ -+void rtw_set_external_auth_status(_adapter *padapter, const void *data, int len); -+ -+u8 rtw_get_oper_ch(_adapter *adapter); -+void rtw_set_oper_ch(_adapter *adapter, u8 ch); -+u8 rtw_get_oper_bw(_adapter *adapter); -+void rtw_set_oper_bw(_adapter *adapter, u8 bw); -+u8 rtw_get_oper_choffset(_adapter *adapter); -+void rtw_set_oper_choffset(_adapter *adapter, u8 offset); -+u8 rtw_get_center_ch(u8 channel, u8 chnl_bw, u8 chnl_offset); -+systime rtw_get_on_oper_ch_time(_adapter *adapter); -+systime rtw_get_on_cur_ch_time(_adapter *adapter); -+ -+u8 rtw_get_offset_by_chbw(u8 ch, u8 bw, u8 *r_offset); -+ -+void set_channel_bwmode(_adapter *padapter, unsigned char channel, unsigned char channel_offset, unsigned short bwmode); -+ -+unsigned int decide_wait_for_beacon_timeout(unsigned int bcn_interval); -+ -+void _clear_cam_entry(_adapter *padapter, u8 entry); -+void write_cam_from_cache(_adapter *adapter, u8 id); -+void rtw_sec_cam_swap(_adapter *adapter, u8 cam_id_a, u8 cam_id_b); -+void rtw_clean_dk_section(_adapter *adapter); -+void rtw_clean_hw_dk_cam(_adapter *adapter); -+ -+/* modify both HW and cache */ -+void write_cam(_adapter *padapter, u8 id, u16 ctrl, u8 *mac, u8 *key); -+void clear_cam_entry(_adapter *padapter, u8 id); -+ -+/* modify cache only */ -+void write_cam_cache(_adapter *adapter, u8 id, u16 ctrl, u8 *mac, u8 *key); -+void clear_cam_cache(_adapter *adapter, u8 id); -+ -+void invalidate_cam_all(_adapter *padapter); -+void CAM_empty_entry(PADAPTER Adapter, u8 ucIndex); -+ -+void flush_all_cam_entry(_adapter *padapter); -+ -+BOOLEAN IsLegal5GChannel(PADAPTER Adapter, u8 channel); -+ -+void site_survey(_adapter *padapter, u8 survey_channel, RT_SCAN_TYPE ScanType); -+u8 collect_bss_info(_adapter *padapter, union recv_frame *precv_frame, WLAN_BSSID_EX *bssid); -+void update_network(WLAN_BSSID_EX *dst, WLAN_BSSID_EX *src, _adapter *padapter, bool update_ie); -+ -+u8 *get_my_bssid(WLAN_BSSID_EX *pnetwork); -+u16 get_beacon_interval(WLAN_BSSID_EX *bss); -+ -+int is_client_associated_to_ap(_adapter *padapter); -+int is_client_associated_to_ibss(_adapter *padapter); -+int is_IBSS_empty(_adapter *padapter); -+ -+unsigned char check_assoc_AP(u8 *pframe, uint len); -+void get_assoc_AP_Vendor(char *vendor, u8 assoc_AP_vendor); -+#ifdef CONFIG_RTS_FULL_BW -+void rtw_parse_sta_vendor_ie_8812(_adapter *adapter, struct sta_info *sta, u8 *tlv_ies, u16 tlv_ies_len); -+#endif/*CONFIG_RTS_FULL_BW*/ -+#ifdef CONFIG_80211AC_VHT -+unsigned char get_vht_mu_bfer_cap(u8 *pframe, uint len); -+#endif -+ -+int WMM_param_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE); -+#ifdef CONFIG_WFD -+void rtw_process_wfd_ie(_adapter *adapter, u8 *ie, u8 ie_len, const char *tag); -+void rtw_process_wfd_ies(_adapter *adapter, u8 *ies, u8 ies_len, const char *tag); -+#endif -+void WMMOnAssocRsp(_adapter *padapter); -+ -+void HT_caps_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE); -+#ifdef ROKU_PRIVATE -+void HT_caps_handler_infra_ap(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE); -+#endif -+void HT_info_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE); -+void HTOnAssocRsp(_adapter *padapter); -+ -+#ifdef ROKU_PRIVATE -+void Supported_rate_infra_ap(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE); -+void Extended_Supported_rate_infra_ap(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE); -+#endif -+ -+void ERP_IE_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE); -+void VCS_update(_adapter *padapter, struct sta_info *psta); -+void update_ldpc_stbc_cap(struct sta_info *psta); -+ -+bool rtw_validate_value(u16 EID, u8 *p, u16 len); -+bool hidden_ssid_ap(WLAN_BSSID_EX *snetwork); -+void rtw_absorb_ssid_ifneed(_adapter *padapter, WLAN_BSSID_EX *bssid, u8 *pframe); -+int rtw_get_bcn_keys(ADAPTER *Adapter, u8 *pframe, u32 packet_len, -+ struct beacon_keys *recv_beacon); -+int validate_beacon_len(u8 *pframe, uint len); -+void rtw_dump_bcn_keys(void *sel, struct beacon_keys *recv_beacon); -+int rtw_check_bcn_info(ADAPTER *Adapter, u8 *pframe, u32 packet_len); -+void update_beacon_info(_adapter *padapter, u8 *pframe, uint len, struct sta_info *psta); -+#ifdef CONFIG_DFS -+void process_csa_ie(_adapter *padapter, u8 *ies, uint ies_len); -+#endif /* CONFIG_DFS */ -+void update_capinfo(PADAPTER Adapter, u16 updateCap); -+void update_wireless_mode(_adapter *padapter); -+void update_tx_basic_rate(_adapter *padapter, u8 modulation); -+void update_sta_basic_rate(struct sta_info *psta, u8 wireless_mode); -+int rtw_ies_get_supported_rate(u8 *ies, uint ies_len, u8 *rate_set, u8 *rate_num); -+ -+/* for sta/adhoc mode */ -+void update_sta_info(_adapter *padapter, struct sta_info *psta); -+unsigned int update_basic_rate(unsigned char *ptn, unsigned int ptn_sz); -+unsigned int update_supported_rate(unsigned char *ptn, unsigned int ptn_sz); -+void Update_RA_Entry(_adapter *padapter, struct sta_info *psta); -+void set_sta_rate(_adapter *padapter, struct sta_info *psta); -+ -+unsigned int receive_disconnect(_adapter *padapter, unsigned char *MacAddr, unsigned short reason, u8 locally_generated); -+ -+unsigned char get_highest_rate_idx(u64 mask); -+unsigned char get_lowest_rate_idx_ex(u64 mask, int start_bit); -+#define get_lowest_rate_idx(mask) get_lowest_rate_idx_ex(mask, 0) -+ -+int support_short_GI(_adapter *padapter, struct HT_caps_element *pHT_caps, u8 bwmode); -+unsigned int is_ap_in_tkip(_adapter *padapter); -+unsigned int is_ap_in_wep(_adapter *padapter); -+unsigned int should_forbid_n_rate(_adapter *padapter); -+ -+void parsing_eapol_packet(_adapter *padapter, u8 *key_payload, struct sta_info *psta, u8 trx_type); -+ -+bool _rtw_camctl_chk_cap(_adapter *adapter, u8 cap); -+void _rtw_camctl_set_flags(_adapter *adapter, u32 flags); -+void rtw_camctl_set_flags(_adapter *adapter, u32 flags); -+void _rtw_camctl_clr_flags(_adapter *adapter, u32 flags); -+void rtw_camctl_clr_flags(_adapter *adapter, u32 flags); -+bool _rtw_camctl_chk_flags(_adapter *adapter, u32 flags); -+ -+struct sec_cam_bmp; -+void dump_sec_cam_map(void *sel, struct sec_cam_bmp *map, u8 max_num); -+void rtw_sec_cam_map_clr_all(struct sec_cam_bmp *map); -+ -+bool _rtw_camid_is_gk(_adapter *adapter, u8 cam_id); -+bool rtw_camid_is_gk(_adapter *adapter, u8 cam_id); -+s16 rtw_camid_search(_adapter *adapter, u8 *addr, s16 kid, s8 gk); -+s16 rtw_camid_alloc(_adapter *adapter, struct sta_info *sta, u8 kid, u8 gk, bool *used); -+void rtw_camid_free(_adapter *adapter, u8 cam_id); -+u8 rtw_get_sec_camid(_adapter *adapter, u8 max_bk_key_num, u8 *sec_key_id); -+ -+struct macid_bmp; -+struct macid_ctl_t; -+void dump_macid_map(void *sel, struct macid_bmp *map, u8 max_num); -+bool rtw_macid_is_set(struct macid_bmp *map, u8 id); -+void rtw_macid_map_clr(struct macid_bmp *map, u8 id); -+bool rtw_macid_is_used(struct macid_ctl_t *macid_ctl, u8 id); -+bool rtw_macid_is_bmc(struct macid_ctl_t *macid_ctl, u8 id); -+u8 rtw_macid_get_iface_bmp(struct macid_ctl_t *macid_ctl, u8 id); -+bool rtw_macid_is_iface_shared(struct macid_ctl_t *macid_ctl, u8 id); -+bool rtw_macid_is_iface_specific(struct macid_ctl_t *macid_ctl, u8 id, _adapter *adapter); -+s8 rtw_macid_get_ch_g(struct macid_ctl_t *macid_ctl, u8 id); -+void rtw_alloc_macid(_adapter *padapter, struct sta_info *psta); -+void rtw_release_macid(_adapter *padapter, struct sta_info *psta); -+u8 rtw_search_max_mac_id(_adapter *padapter); -+void rtw_macid_ctl_set_h2c_msr(struct macid_ctl_t *macid_ctl, u8 id, u8 h2c_msr); -+void rtw_macid_ctl_set_bw(struct macid_ctl_t *macid_ctl, u8 id, u8 bw); -+void rtw_macid_ctl_set_vht_en(struct macid_ctl_t *macid_ctl, u8 id, u8 en); -+void rtw_macid_ctl_set_rate_bmp0(struct macid_ctl_t *macid_ctl, u8 id, u32 bmp); -+void rtw_macid_ctl_set_rate_bmp1(struct macid_ctl_t *macid_ctl, u8 id, u32 bmp); -+void rtw_macid_ctl_init_sleep_reg(struct macid_ctl_t *macid_ctl, u16 m0, u16 m1, u16 m2, u16 m3); -+void rtw_macid_ctl_init(struct macid_ctl_t *macid_ctl); -+void rtw_macid_ctl_deinit(struct macid_ctl_t *macid_ctl); -+u8 rtw_iface_bcmc_id_get(_adapter *padapter); -+void rtw_iface_bcmc_id_set(_adapter *padapter, u8 mac_id); -+#if defined(DBG_CONFIG_ERROR_RESET) && defined(CONFIG_CONCURRENT_MODE) -+void rtw_iface_bcmc_sec_cam_map_restore(_adapter *adapter); -+#endif -+bool rtw_bmp_is_set(const u8 *bmp, u8 bmp_len, u8 id); -+void rtw_bmp_set(u8 *bmp, u8 bmp_len, u8 id); -+void rtw_bmp_clear(u8 *bmp, u8 bmp_len, u8 id); -+bool rtw_bmp_not_empty(const u8 *bmp, u8 bmp_len); -+bool rtw_bmp_not_empty_exclude_bit0(const u8 *bmp, u8 bmp_len); -+ -+#ifdef CONFIG_AP_MODE -+bool rtw_tim_map_is_set(_adapter *padapter, const u8 *map, u8 id); -+void rtw_tim_map_set(_adapter *padapter, u8 *map, u8 id); -+void rtw_tim_map_clear(_adapter *padapter, u8 *map, u8 id); -+bool rtw_tim_map_anyone_be_set(_adapter *padapter, const u8 *map); -+bool rtw_tim_map_anyone_be_set_exclude_aid0(_adapter *padapter, const u8 *map); -+#endif /* CONFIG_AP_MODE */ -+ -+u32 report_join_res(_adapter *padapter, int aid_res, u16 status); -+void report_survey_event(_adapter *padapter, union recv_frame *precv_frame); -+void report_surveydone_event(_adapter *padapter); -+u32 report_del_sta_event(_adapter *padapter, unsigned char *MacAddr, unsigned short reason, bool enqueue, u8 locally_generated); -+void report_add_sta_event(_adapter *padapter, unsigned char *MacAddr); -+bool rtw_port_switch_chk(_adapter *adapter); -+void report_wmm_edca_update(_adapter *padapter); -+ -+void beacon_timing_control(_adapter *padapter); -+u8 chk_bmc_sleepq_cmd(_adapter *padapter); -+extern u8 set_tx_beacon_cmd(_adapter *padapter); -+unsigned int setup_beacon_frame(_adapter *padapter, unsigned char *beacon_frame); -+void update_mgnt_tx_rate(_adapter *padapter, u8 rate); -+void update_monitor_frame_attrib(_adapter *padapter, struct pkt_attrib *pattrib); -+void update_mgntframe_attrib(_adapter *padapter, struct pkt_attrib *pattrib); -+void update_mgntframe_attrib_addr(_adapter *padapter, struct xmit_frame *pmgntframe); -+void dump_mgntframe(_adapter *padapter, struct xmit_frame *pmgntframe); -+s32 dump_mgntframe_and_wait(_adapter *padapter, struct xmit_frame *pmgntframe, int timeout_ms); -+s32 dump_mgntframe_and_wait_ack(_adapter *padapter, struct xmit_frame *pmgntframe); -+s32 dump_mgntframe_and_wait_ack_timeout(_adapter *padapter, struct xmit_frame *pmgntframe, int timeout_ms); -+ -+#ifdef CONFIG_P2P -+int get_reg_classes_full_count(struct p2p_channels *channel_list); -+void issue_probersp_p2p(_adapter *padapter, unsigned char *da); -+void issue_p2p_provision_request(_adapter *padapter, u8 *pssid, u8 ussidlen, u8 *pdev_raddr); -+void issue_p2p_GO_request(_adapter *padapter, u8 *raddr); -+void issue_probereq_p2p(_adapter *padapter, u8 *da); -+int issue_probereq_p2p_ex(_adapter *adapter, u8 *da, int try_cnt, int wait_ms); -+void issue_p2p_invitation_response(_adapter *padapter, u8 *raddr, u8 dialogToken, u8 success); -+void issue_p2p_invitation_request(_adapter *padapter, u8 *raddr); -+#endif /* CONFIG_P2P */ -+void issue_beacon(_adapter *padapter, int timeout_ms); -+void issue_probersp(_adapter *padapter, unsigned char *da, u8 is_valid_p2p_probereq); -+void _issue_assocreq(_adapter *padapter, u8 is_assoc); -+void issue_assocreq(_adapter *padapter); -+void issue_reassocreq(_adapter *padapter); -+void issue_asocrsp(_adapter *padapter, unsigned short status, struct sta_info *pstat, int pkt_type); -+void issue_auth(_adapter *padapter, struct sta_info *psta, unsigned short status); -+void issue_probereq(_adapter *padapter, const NDIS_802_11_SSID *pssid, const u8 *da); -+s32 issue_probereq_ex(_adapter *padapter, const NDIS_802_11_SSID *pssid, const u8 *da, u8 ch, bool append_wps, int try_cnt, int wait_ms); -+int issue_nulldata(_adapter *padapter, unsigned char *da, unsigned int power_mode, int try_cnt, int wait_ms); -+int issue_qos_nulldata(_adapter *padapter, unsigned char *da, u16 tid, u8 ps, int try_cnt, int wait_ms); -+int issue_deauth(_adapter *padapter, unsigned char *da, unsigned short reason); -+int issue_deauth_ex(_adapter *padapter, u8 *da, unsigned short reason, int try_cnt, int wait_ms); -+void issue_action_spct_ch_switch(_adapter *padapter, u8 *ra, u8 new_ch, u8 ch_offset); -+void issue_addba_req(_adapter *adapter, unsigned char *ra, u8 tid); -+void issue_addba_rsp(_adapter *adapter, unsigned char *ra, u8 tid, u16 status, u8 size); -+u8 issue_addba_rsp_wait_ack(_adapter *adapter, unsigned char *ra, u8 tid, u16 status, u8 size, int try_cnt, int wait_ms); -+void issue_del_ba(_adapter *adapter, unsigned char *ra, u8 tid, u16 reason, u8 initiator); -+int issue_del_ba_ex(_adapter *adapter, unsigned char *ra, u8 tid, u16 reason, u8 initiator, int try_cnt, int wait_ms); -+void issue_action_BSSCoexistPacket(_adapter *padapter); -+ -+#ifdef CONFIG_IEEE80211W -+void issue_action_SA_Query(_adapter *padapter, unsigned char *raddr, unsigned char action, unsigned short tid, u8 key_type); -+int issue_deauth_11w(_adapter *padapter, unsigned char *da, unsigned short reason, u8 key_type); -+#endif /* CONFIG_IEEE80211W */ -+int issue_action_SM_PS(_adapter *padapter , unsigned char *raddr , u8 NewMimoPsMode); -+int issue_action_SM_PS_wait_ack(_adapter *padapter, unsigned char *raddr, u8 NewMimoPsMode, int try_cnt, int wait_ms); -+ -+unsigned int send_delba_sta_tid(_adapter *adapter, u8 initiator, struct sta_info *sta, u8 tid, u8 force); -+unsigned int send_delba_sta_tid_wait_ack(_adapter *adapter, u8 initiator, struct sta_info *sta, u8 tid, u8 force); -+ -+unsigned int send_delba(_adapter *padapter, u8 initiator, u8 *addr); -+unsigned int send_beacon(_adapter *padapter); -+ -+void start_clnt_assoc(_adapter *padapter); -+void start_clnt_auth(_adapter *padapter); -+void start_clnt_join(_adapter *padapter); -+void start_create_ibss(_adapter *padapter); -+ -+unsigned int OnAssocReq(_adapter *padapter, union recv_frame *precv_frame); -+unsigned int OnAssocRsp(_adapter *padapter, union recv_frame *precv_frame); -+unsigned int OnProbeReq(_adapter *padapter, union recv_frame *precv_frame); -+unsigned int OnProbeRsp(_adapter *padapter, union recv_frame *precv_frame); -+unsigned int DoReserved(_adapter *padapter, union recv_frame *precv_frame); -+unsigned int OnBeacon(_adapter *padapter, union recv_frame *precv_frame); -+unsigned int OnAtim(_adapter *padapter, union recv_frame *precv_frame); -+unsigned int OnDisassoc(_adapter *padapter, union recv_frame *precv_frame); -+unsigned int OnAuth(_adapter *padapter, union recv_frame *precv_frame); -+unsigned int OnAuthClient(_adapter *padapter, union recv_frame *precv_frame); -+unsigned int OnDeAuth(_adapter *padapter, union recv_frame *precv_frame); -+unsigned int OnAction(_adapter *padapter, union recv_frame *precv_frame); -+ -+unsigned int on_action_spct(_adapter *padapter, union recv_frame *precv_frame); -+unsigned int OnAction_qos(_adapter *padapter, union recv_frame *precv_frame); -+unsigned int OnAction_dls(_adapter *padapter, union recv_frame *precv_frame); -+#ifdef CONFIG_RTW_WNM -+unsigned int on_action_wnm(_adapter *adapter, union recv_frame *rframe); -+#endif -+ -+#define RX_AMPDU_ACCEPT_INVALID 0xFF -+#define RX_AMPDU_SIZE_INVALID 0xFF -+ -+enum rx_ampdu_reason { -+ RX_AMPDU_DRV_FIXED = 1, -+ RX_AMPDU_BTCOEX = 2, /* not used, because BTCOEX has its own variable management */ -+ RX_AMPDU_DRV_SCAN = 3, -+}; -+u8 rtw_rx_ampdu_size(_adapter *adapter); -+bool rtw_rx_ampdu_is_accept(_adapter *adapter); -+bool rtw_rx_ampdu_set_size(_adapter *adapter, u8 size, u8 reason); -+bool rtw_rx_ampdu_set_accept(_adapter *adapter, u8 accept, u8 reason); -+u8 rx_ampdu_apply_sta_tid(_adapter *adapter, struct sta_info *sta, u8 tid, u8 accept, u8 size); -+u8 rx_ampdu_size_sta_limit(_adapter *adapter, struct sta_info *sta); -+u8 rx_ampdu_apply_sta(_adapter *adapter, struct sta_info *sta, u8 accept, u8 size); -+u16 rtw_rx_ampdu_apply(_adapter *adapter); -+ -+unsigned int OnAction_back(_adapter *padapter, union recv_frame *precv_frame); -+unsigned int on_action_public(_adapter *padapter, union recv_frame *precv_frame); -+unsigned int OnAction_ft(_adapter *padapter, union recv_frame *precv_frame); -+unsigned int OnAction_ht(_adapter *padapter, union recv_frame *precv_frame); -+#ifdef CONFIG_IEEE80211W -+unsigned int OnAction_sa_query(_adapter *padapter, union recv_frame *precv_frame); -+#endif /* CONFIG_IEEE80211W */ -+unsigned int on_action_rm(_adapter *padapter, union recv_frame *precv_frame); -+unsigned int OnAction_wmm(_adapter *padapter, union recv_frame *precv_frame); -+unsigned int OnAction_vht(_adapter *padapter, union recv_frame *precv_frame); -+unsigned int OnAction_p2p(_adapter *padapter, union recv_frame *precv_frame); -+ -+#ifdef CONFIG_RTW_80211R -+void rtw_ft_update_bcn(_adapter *padapter, union recv_frame *precv_frame); -+void rtw_ft_start_clnt_join(_adapter *padapter); -+u8 rtw_ft_update_rsnie(_adapter *padapter, u8 bwrite, -+ struct pkt_attrib *pattrib, u8 **pframe); -+void rtw_ft_build_auth_req_ies(_adapter *padapter, -+ struct pkt_attrib *pattrib, u8 **pframe); -+void rtw_ft_build_assoc_req_ies(_adapter *padapter, -+ u8 is_reassoc, struct pkt_attrib *pattrib, u8 **pframe); -+u8 rtw_ft_update_auth_rsp_ies(_adapter *padapter, u8 *pframe, u32 len); -+void rtw_ft_start_roam(_adapter *padapter, u8 *pTargetAddr); -+void rtw_ft_issue_action_req(_adapter *padapter, u8 *pTargetAddr); -+void rtw_ft_report_evt(_adapter *padapter); -+void rtw_ft_report_reassoc_evt(_adapter *padapter, u8 *pMacAddr); -+void rtw_ft_link_timer_hdl(void *ctx); -+void rtw_ft_roam_timer_hdl(void *ctx); -+void rtw_ft_roam_status_reset(_adapter *padapter); -+#endif -+#ifdef CONFIG_RTW_WNM -+void rtw_wnm_roam_scan_hdl(void *ctx); -+void rtw_wnm_process_btm_req(_adapter *padapter, u8* pframe, u32 frame_len); -+void rtw_wnm_reset_btm_candidate(struct roam_nb_info *pnb); -+void rtw_wnm_reset_btm_state(_adapter *padapter); -+void rtw_wnm_issue_action(_adapter *padapter, u8 action, u8 reason); -+#endif -+#if defined(CONFIG_RTW_WNM) || defined(CONFIG_RTW_80211K) -+u32 rtw_wnm_btm_candidates_survey(_adapter *padapter, u8* pframe, u32 elem_len, u8 is_preference); -+#endif -+void mlmeext_joinbss_event_callback(_adapter *padapter, int join_res); -+void mlmeext_sta_del_event_callback(_adapter *padapter); -+void mlmeext_sta_add_event_callback(_adapter *padapter, struct sta_info *psta); -+ -+void linked_status_chk(_adapter *padapter, u8 from_timer); -+ -+#define rtw_get_bcn_cnt(adapter) (adapter->mlmeextpriv.cur_bcn_cnt) -+#define rtw_get_bcn_dtim_period(adapter) (adapter->mlmeextpriv.dtim) -+void rtw_collect_bcn_info(_adapter *adapter); -+ -+void _linked_info_dump(_adapter *padapter); -+ -+void survey_timer_hdl(void *ctx); -+#ifdef CONFIG_RTW_REPEATER_SON -+void rson_timer_hdl(void *ctx); -+#endif -+void link_timer_hdl(void *ctx); -+void addba_timer_hdl(void *ctx); -+#ifdef CONFIG_IEEE80211W -+void sa_query_timer_hdl(void *ctx); -+#endif /* CONFIG_IEEE80211W */ -+#if 0 -+void reauth_timer_hdl(_adapter *padapter); -+void reassoc_timer_hdl(_adapter *padapter); -+#endif -+ -+#define set_survey_timer(mlmeext, ms) \ -+ do { \ -+ /*RTW_INFO("%s set_survey_timer(%p, %d)\n", __FUNCTION__, (mlmeext), (ms));*/ \ -+ _set_timer(&(mlmeext)->survey_timer, (ms)); \ -+ } while (0) -+ -+#define set_link_timer(mlmeext, ms) \ -+ do { \ -+ /*RTW_INFO("%s set_link_timer(%p, %d)\n", __FUNCTION__, (mlmeext), (ms));*/ \ -+ _set_timer(&(mlmeext)->link_timer, (ms)); \ -+ } while (0) -+ -+bool rtw_is_basic_rate_cck(u8 rate); -+bool rtw_is_basic_rate_ofdm(u8 rate); -+bool rtw_is_basic_rate_mix(u8 rate); -+ -+extern int cckrates_included(unsigned char *rate, int ratelen); -+extern int cckratesonly_included(unsigned char *rate, int ratelen); -+ -+extern void process_addba_req(_adapter *padapter, u8 *paddba_req, u8 *addr); -+ -+extern void update_TSF(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len); -+extern void correct_TSF(_adapter *padapter, u8 mlme_state); -+#ifdef CONFIG_BCN_RECV_TIME -+void rtw_rx_bcn_time_update(_adapter *adapter, uint bcn_len, u8 data_rate); -+#endif -+extern u8 traffic_status_watchdog(_adapter *padapter, u8 from_timer); -+ -+void rtw_process_bar_frame(_adapter *padapter, union recv_frame *precv_frame); -+void rtw_join_done_chk_ch(_adapter *padapter, int join_res); -+ -+int rtw_chk_start_clnt_join(_adapter *padapter, u8 *ch, u8 *bw, u8 *offset); -+ -+#ifdef CONFIG_PLATFORM_ARM_SUN8I -+ #define BUSY_TRAFFIC_SCAN_DENY_PERIOD 8000 -+#else -+ #define BUSY_TRAFFIC_SCAN_DENY_PERIOD 12000 -+#endif -+ -+struct cmd_hdl { -+ uint parmsize; -+ u8(*h2cfuns)(struct _ADAPTER *padapter, u8 *pbuf); -+}; -+ -+void rtw_leave_opch(_adapter *adapter); -+void rtw_back_opch(_adapter *adapter); -+ -+u8 read_macreg_hdl(_adapter *padapter, u8 *pbuf); -+u8 write_macreg_hdl(_adapter *padapter, u8 *pbuf); -+u8 read_bbreg_hdl(_adapter *padapter, u8 *pbuf); -+u8 write_bbreg_hdl(_adapter *padapter, u8 *pbuf); -+u8 read_rfreg_hdl(_adapter *padapter, u8 *pbuf); -+u8 write_rfreg_hdl(_adapter *padapter, u8 *pbuf); -+ -+ -+u8 NULL_hdl(_adapter *padapter, u8 *pbuf); -+u8 join_cmd_hdl(_adapter *padapter, u8 *pbuf); -+u8 disconnect_hdl(_adapter *padapter, u8 *pbuf); -+u8 createbss_hdl(_adapter *padapter, u8 *pbuf); -+#ifdef CONFIG_AP_MODE -+u8 stop_ap_hdl(_adapter *adapter); -+#endif -+u8 setopmode_hdl(_adapter *padapter, u8 *pbuf); -+u8 sitesurvey_cmd_hdl(_adapter *padapter, u8 *pbuf); -+u8 setauth_hdl(_adapter *padapter, u8 *pbuf); -+u8 setkey_hdl(_adapter *padapter, u8 *pbuf); -+u8 set_stakey_hdl(_adapter *padapter, u8 *pbuf); -+u8 set_assocsta_hdl(_adapter *padapter, u8 *pbuf); -+u8 del_assocsta_hdl(_adapter *padapter, u8 *pbuf); -+u8 add_ba_hdl(_adapter *padapter, unsigned char *pbuf); -+u8 add_ba_rsp_hdl(_adapter *padapter, unsigned char *pbuf); -+ -+void rtw_ap_wep_pk_setting(_adapter *adapter, struct sta_info *psta); -+ -+u8 mlme_evt_hdl(_adapter *padapter, unsigned char *pbuf); -+u8 h2c_msg_hdl(_adapter *padapter, unsigned char *pbuf); -+u8 chk_bmc_sleepq_hdl(_adapter *padapter, unsigned char *pbuf); -+u8 tx_beacon_hdl(_adapter *padapter, unsigned char *pbuf); -+u8 rtw_set_chbw_hdl(_adapter *padapter, u8 *pbuf); -+u8 set_chplan_hdl(_adapter *padapter, unsigned char *pbuf); -+u8 led_blink_hdl(_adapter *padapter, unsigned char *pbuf); -+u8 set_csa_hdl(_adapter *padapter, unsigned char *pbuf); /* Kurt: Handling DFS channel switch announcement ie. */ -+u8 tdls_hdl(_adapter *padapter, unsigned char *pbuf); -+u8 run_in_thread_hdl(_adapter *padapter, u8 *pbuf); -+u8 rtw_getmacreg_hdl(_adapter *padapter, u8 *pbuf); -+ -+int rtw_sae_preprocess(_adapter *adapter, const u8 *buf, u32 len, u8 tx); -+ -+#define GEN_DRV_CMD_HANDLER(size, cmd) {size, &cmd ## _hdl}, -+#define GEN_MLME_EXT_HANDLER(size, cmd) {size, cmd}, -+ -+#ifdef _RTW_CMD_C_ -+ -+struct cmd_hdl wlancmds[] = { -+ GEN_DRV_CMD_HANDLER(sizeof(struct readMAC_parm), rtw_getmacreg) /*0*/ -+ GEN_DRV_CMD_HANDLER(0, NULL) -+ GEN_DRV_CMD_HANDLER(0, NULL) -+ GEN_DRV_CMD_HANDLER(0, NULL) -+ GEN_DRV_CMD_HANDLER(0, NULL) -+ GEN_DRV_CMD_HANDLER(0, NULL) -+ GEN_MLME_EXT_HANDLER(0, NULL) -+ GEN_MLME_EXT_HANDLER(0, NULL) -+ GEN_MLME_EXT_HANDLER(0, NULL) -+ GEN_MLME_EXT_HANDLER(0, NULL) -+ GEN_MLME_EXT_HANDLER(0, NULL) /*10*/ -+ GEN_MLME_EXT_HANDLER(0, NULL) -+ GEN_MLME_EXT_HANDLER(0, NULL) -+ GEN_MLME_EXT_HANDLER(0, NULL) -+ GEN_MLME_EXT_HANDLER(sizeof(struct joinbss_parm), join_cmd_hdl) /*14*/ -+ GEN_MLME_EXT_HANDLER(sizeof(struct disconnect_parm), disconnect_hdl) -+ GEN_MLME_EXT_HANDLER(sizeof(struct createbss_parm), createbss_hdl) -+ GEN_MLME_EXT_HANDLER(sizeof(struct setopmode_parm), setopmode_hdl) -+ GEN_MLME_EXT_HANDLER(sizeof(struct sitesurvey_parm), sitesurvey_cmd_hdl) /*18*/ -+ GEN_MLME_EXT_HANDLER(sizeof(struct setauth_parm), setauth_hdl) -+ GEN_MLME_EXT_HANDLER(sizeof(struct setkey_parm), setkey_hdl) /*20*/ -+ GEN_MLME_EXT_HANDLER(sizeof(struct set_stakey_parm), set_stakey_hdl) -+ GEN_MLME_EXT_HANDLER(sizeof(struct set_assocsta_parm), NULL) -+ GEN_MLME_EXT_HANDLER(sizeof(struct del_assocsta_parm), NULL) -+ GEN_MLME_EXT_HANDLER(sizeof(struct setstapwrstate_parm), NULL) -+ GEN_MLME_EXT_HANDLER(sizeof(struct setbasicrate_parm), NULL) -+ GEN_MLME_EXT_HANDLER(sizeof(struct getbasicrate_parm), NULL) -+ GEN_MLME_EXT_HANDLER(sizeof(struct setdatarate_parm), NULL) -+ GEN_MLME_EXT_HANDLER(sizeof(struct getdatarate_parm), NULL) -+ GEN_MLME_EXT_HANDLER(0, NULL) -+ GEN_MLME_EXT_HANDLER(0, NULL) /*30*/ -+ GEN_MLME_EXT_HANDLER(sizeof(struct setphy_parm), NULL) -+ GEN_MLME_EXT_HANDLER(sizeof(struct getphy_parm), NULL) -+ GEN_MLME_EXT_HANDLER(0, NULL) -+ GEN_MLME_EXT_HANDLER(0, NULL) -+ GEN_MLME_EXT_HANDLER(0, NULL) -+ GEN_MLME_EXT_HANDLER(0, NULL) -+ GEN_MLME_EXT_HANDLER(0, NULL) -+ GEN_MLME_EXT_HANDLER(0, NULL) -+ GEN_MLME_EXT_HANDLER(0, NULL) -+ GEN_MLME_EXT_HANDLER(0, NULL) /*40*/ -+ GEN_MLME_EXT_HANDLER(0, NULL) -+ GEN_MLME_EXT_HANDLER(0, NULL) -+ GEN_MLME_EXT_HANDLER(0, NULL) -+ GEN_MLME_EXT_HANDLER(0, NULL) -+ GEN_MLME_EXT_HANDLER(sizeof(struct addBaReq_parm), add_ba_hdl) -+ GEN_MLME_EXT_HANDLER(sizeof(struct set_ch_parm), rtw_set_chbw_hdl) /* 46 */ -+ GEN_MLME_EXT_HANDLER(0, NULL) -+ GEN_MLME_EXT_HANDLER(0, NULL) -+ GEN_MLME_EXT_HANDLER(0, NULL) -+ GEN_MLME_EXT_HANDLER(0, NULL) /*50*/ -+ GEN_MLME_EXT_HANDLER(0, NULL) -+ GEN_MLME_EXT_HANDLER(0, NULL) -+ GEN_MLME_EXT_HANDLER(0, NULL) -+ GEN_MLME_EXT_HANDLER(0, NULL) -+ GEN_MLME_EXT_HANDLER(sizeof(struct Tx_Beacon_param), tx_beacon_hdl) /*55*/ -+ -+ GEN_MLME_EXT_HANDLER(0, mlme_evt_hdl) /*56*/ -+ GEN_MLME_EXT_HANDLER(0, rtw_drvextra_cmd_hdl) /*57*/ -+ -+ GEN_MLME_EXT_HANDLER(0, h2c_msg_hdl) /*58*/ -+ GEN_MLME_EXT_HANDLER(sizeof(struct SetChannelPlan_param), set_chplan_hdl) /*59*/ -+ GEN_MLME_EXT_HANDLER(sizeof(struct LedBlink_param), led_blink_hdl) /*60*/ -+ -+ GEN_MLME_EXT_HANDLER(0, set_csa_hdl) /*61*/ -+ GEN_MLME_EXT_HANDLER(sizeof(struct TDLSoption_param), tdls_hdl) /*62*/ -+ GEN_MLME_EXT_HANDLER(0, chk_bmc_sleepq_hdl) /*63*/ -+ GEN_MLME_EXT_HANDLER(sizeof(struct RunInThread_param), run_in_thread_hdl) /*64*/ -+ GEN_MLME_EXT_HANDLER(sizeof(struct addBaRsp_parm), add_ba_rsp_hdl) /* 65 */ -+ GEN_MLME_EXT_HANDLER(sizeof(struct rm_event), rm_post_event_hdl) /* 66 */ -+}; -+ -+#endif -+ -+struct C2HEvent_Header { -+ -+#ifdef CONFIG_LITTLE_ENDIAN -+ -+ unsigned int len:16; -+ unsigned int ID:8; -+ unsigned int seq:8; -+ -+#elif defined(CONFIG_BIG_ENDIAN) -+ -+ unsigned int seq:8; -+ unsigned int ID:8; -+ unsigned int len:16; -+ -+#else -+ -+# error "Must be LITTLE or BIG Endian" -+ -+#endif -+ -+ unsigned int rsvd; -+ -+}; -+ -+void rtw_dummy_event_callback(_adapter *adapter , u8 *pbuf); -+void rtw_fwdbg_event_callback(_adapter *adapter , u8 *pbuf); -+ -+enum rtw_c2h_event { -+ GEN_EVT_CODE(_Read_MACREG) = 0, /*0*/ -+ GEN_EVT_CODE(_Read_BBREG), -+ GEN_EVT_CODE(_Read_RFREG), -+ GEN_EVT_CODE(_Read_EEPROM), -+ GEN_EVT_CODE(_Read_EFUSE), -+ GEN_EVT_CODE(_Read_CAM), /*5*/ -+ GEN_EVT_CODE(_Get_BasicRate), -+ GEN_EVT_CODE(_Get_DataRate), -+ GEN_EVT_CODE(_Survey), /*8*/ -+ GEN_EVT_CODE(_SurveyDone), /*9*/ -+ -+ GEN_EVT_CODE(_JoinBss) , /*10*/ -+ GEN_EVT_CODE(_AddSTA), -+ GEN_EVT_CODE(_DelSTA), -+ GEN_EVT_CODE(_AtimDone) , -+ GEN_EVT_CODE(_TX_Report), -+ GEN_EVT_CODE(_CCX_Report), /*15*/ -+ GEN_EVT_CODE(_DTM_Report), -+ GEN_EVT_CODE(_TX_Rate_Statistics), -+ GEN_EVT_CODE(_C2HLBK), -+ GEN_EVT_CODE(_FWDBG), -+ GEN_EVT_CODE(_C2HFEEDBACK), /*20*/ -+ GEN_EVT_CODE(_ADDBA), -+ GEN_EVT_CODE(_C2HBCN), -+ GEN_EVT_CODE(_ReportPwrState), /* filen: only for PCIE, USB */ -+ GEN_EVT_CODE(_CloseRF), /* filen: only for PCIE, work around ASPM */ -+ GEN_EVT_CODE(_WMM), /*25*/ -+#ifdef CONFIG_IEEE80211W -+ GEN_EVT_CODE(_TimeoutSTA), -+#endif /* CONFIG_IEEE80211W */ -+#ifdef CONFIG_RTW_80211R -+ GEN_EVT_CODE(_FT_REASSOC), -+#endif -+ MAX_C2HEVT -+}; -+ -+ -+#ifdef _RTW_MLME_EXT_C_ -+ -+static struct fwevent wlanevents[] = { -+ {0, rtw_dummy_event_callback}, /*0*/ -+ {0, NULL}, -+ {0, NULL}, -+ {0, NULL}, -+ {0, NULL}, -+ {0, NULL}, -+ {0, NULL}, -+ {0, NULL}, -+ {0, &rtw_survey_event_callback}, /*8*/ -+ {sizeof(struct surveydone_event), &rtw_surveydone_event_callback}, /*9*/ -+ -+ {0, &rtw_joinbss_event_callback}, /*10*/ -+ {sizeof(struct stassoc_event), &rtw_stassoc_event_callback}, -+ {sizeof(struct stadel_event), &rtw_stadel_event_callback}, -+ {0, &rtw_atimdone_event_callback}, -+ {0, rtw_dummy_event_callback}, -+ {0, NULL}, /*15*/ -+ {0, NULL}, -+ {0, NULL}, -+ {0, NULL}, -+ {0, rtw_fwdbg_event_callback}, -+ {0, NULL}, /*20*/ -+ {0, NULL}, -+ {0, NULL}, -+ {0, &rtw_cpwm_event_callback}, -+ {0, NULL}, -+ {0, &rtw_wmm_event_callback}, /*25*/ -+#ifdef CONFIG_IEEE80211W -+ {sizeof(struct stadel_event), &rtw_sta_timeout_event_callback}, -+#endif /* CONFIG_IEEE80211W */ -+#ifdef CONFIG_RTW_80211R -+ {sizeof(struct stassoc_event), &rtw_ft_reassoc_event_callback}, -+#endif -+}; -+ -+#endif/* _RTW_MLME_EXT_C_ */ -+ -+#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_mp.h linux-5.8/3rdparty/rtl8812au/include/rtw_mp.h -new file mode 100644 -index 000000000..6dbdd87ca ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_mp.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_mp.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_mp.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_mp.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_mp.h 2021-03-07 18:16:17.090957755 +0200 @@ -0,0 +1,938 @@ +/****************************************************************************** + * @@ -405337,11 +401741,9 @@ index 000000000..6dbdd87ca + struct iw_request_info *info, + struct iw_point *wrqu, char *extra); +#endif /* _RTW_MP_H_ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_mp_ioctl.h linux-5.8/3rdparty/rtl8812au/include/rtw_mp_ioctl.h -new file mode 100644 -index 000000000..a9dabfcef ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_mp_ioctl.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_mp_ioctl.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_mp_ioctl.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_mp_ioctl.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_mp_ioctl.h 2021-03-07 18:16:17.091957802 +0200 @@ -0,0 +1,570 @@ +/****************************************************************************** + * @@ -405913,11 +402315,9 @@ index 000000000..a9dabfcef +#endif /* _RTW_MP_IOCTL_C_ */ + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_mp_phy_regdef.h linux-5.8/3rdparty/rtl8812au/include/rtw_mp_phy_regdef.h -new file mode 100644 -index 000000000..be627800e ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_mp_phy_regdef.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_mp_phy_regdef.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_mp_phy_regdef.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_mp_phy_regdef.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_mp_phy_regdef.h 2021-03-07 18:16:17.091957802 +0200 @@ -0,0 +1,1094 @@ +/****************************************************************************** + * @@ -407013,11 +403413,9 @@ index 000000000..be627800e + + +#endif /* __INC_HAL8192SPHYREG_H */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_odm.h linux-5.8/3rdparty/rtl8812au/include/rtw_odm.h -new file mode 100644 -index 000000000..15fa2b90c ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_odm.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_odm.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_odm.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_odm.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_odm.h 2021-03-07 18:16:17.091957802 +0200 @@ -0,0 +1,97 @@ +/****************************************************************************** + * @@ -407116,11 +403514,9 @@ index 000000000..15fa2b90c +void rtw_odm_parse_rx_phy_status_chinfo(union recv_frame *rframe, u8 *phys); + +#endif /* __RTW_ODM_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_p2p.h linux-5.8/3rdparty/rtl8812au/include/rtw_p2p.h -new file mode 100644 -index 000000000..1f985ad1b ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_p2p.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_p2p.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_p2p.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_p2p.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_p2p.h 2021-03-07 18:16:17.091957802 +0200 @@ -0,0 +1,169 @@ +/****************************************************************************** + * @@ -407291,11 +403687,9 @@ index 000000000..1f985ad1b +#endif /* CONFIG_P2P */ + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_pwrctrl.h linux-5.8/3rdparty/rtl8812au/include/rtw_pwrctrl.h -new file mode 100644 -index 000000000..8eac09495 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_pwrctrl.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_pwrctrl.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_pwrctrl.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_pwrctrl.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_pwrctrl.h 2021-03-07 18:16:17.091957802 +0200 @@ -0,0 +1,609 @@ +/****************************************************************************** + * @@ -407906,11 +404300,9 @@ index 000000000..8eac09495 +void rtw_ssmps_enter(_adapter *adapter, struct sta_info *sta); +void rtw_ssmps_leave(_adapter *adapter, struct sta_info *sta); +#endif /* __RTL871X_PWRCTRL_H_ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_qos.h linux-5.8/3rdparty/rtl8812au/include/rtw_qos.h -new file mode 100644 -index 000000000..8e1d013e1 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_qos.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_qos.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_qos.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_qos.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_qos.h 2021-03-07 18:16:17.091957802 +0200 @@ -0,0 +1,66 @@ +/****************************************************************************** + * @@ -407978,12 +404370,10 @@ index 000000000..8e1d013e1 + + +#endif /* _RTL871X_QOS_H_ */ -\ No newline at end of file -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_recv.h linux-5.8/3rdparty/rtl8812au/include/rtw_recv.h -new file mode 100644 -index 000000000..d6422a1d2 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_recv.h +\ Ingen nyrad vid filslut +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_recv.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_recv.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_recv.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_recv.h 2021-03-07 18:16:17.091957802 +0200 @@ -0,0 +1,886 @@ +/****************************************************************************** + * @@ -408871,12 +405261,10 @@ index 000000000..d6422a1d2 +void count_rx_stats(_adapter *padapter, union recv_frame *prframe, struct sta_info *sta); + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_rf.h linux-5.8/3rdparty/rtl8812au/include/rtw_rf.h -new file mode 100644 -index 000000000..5733894d4 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_rf.h -@@ -0,0 +1,238 @@ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_rf.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_rf.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_rf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_rf.h 2021-03-07 18:16:17.091957802 +0200 +@@ -0,0 +1,240 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -408904,7 +405292,7 @@ index 000000000..5733894d4 + +#define CENTER_CH_2G_40M_NUM 9 +#define CENTER_CH_2G_NUM 14 -+#define CENTER_CH_5G_20M_NUM 28 /* 20M center channels */ ++#define CENTER_CH_5G_20M_NUM (28+16) /* 20M center channels */ +#define CENTER_CH_5G_40M_NUM 14 /* 40M center channels */ +#define CENTER_CH_5G_80M_NUM 7 /* 80M center channels */ +#define CENTER_CH_5G_160M_NUM 3 /* 160M center channels */ @@ -408922,7 +405310,9 @@ index 000000000..5733894d4 + +extern u8 center_ch_5g_20m[CENTER_CH_5G_20M_NUM]; +extern u8 center_ch_5g_40m[CENTER_CH_5G_40M_NUM]; ++#if 0 +extern u8 center_ch_5g_20m_40m[CENTER_CH_5G_20M_NUM + CENTER_CH_5G_40M_NUM]; ++#endif +extern u8 center_ch_5g_80m[CENTER_CH_5G_80M_NUM]; +extern u8 center_ch_5g_all[CENTER_CH_5G_ALL_NUM]; + @@ -409115,105 +405505,9 @@ index 000000000..5733894d4 +bool rtw_is_long_cac_ch(u8 ch, u8 bw, u8 offset, u8 dfs_region); + +#endif /* _RTL8711_RF_H_ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_rm.h linux-5.8/3rdparty/rtl8812au/include/rtw_rm.h -new file mode 100644 -index 000000000..9efcf1307 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_rm.h -@@ -0,0 +1,88 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+ -+#ifndef __RTW_RM_H_ -+#define __RTW_RM_H_ -+ -+u8 rm_post_event_hdl(_adapter *padapter, u8 *pbuf); -+ -+#define RM_TIMER_NUM 32 -+#define RM_ALL_MEAS BIT(1) -+#define RM_ID_FOR_ALL(aid) ((aid<<16)|RM_ALL_MEAS) -+ -+#define RM_CAP_ARG(x) ((u8 *)(x))[4], ((u8 *)(x))[3], ((u8 *)(x))[2], ((u8 *)(x))[1], ((u8 *)(x))[0] -+#define RM_CAP_FMT "%02x %02x%02x %02x%02x" -+ -+/* remember to modify rm_event_name() when adding new event */ -+enum RM_EV_ID { -+ RM_EV_state_in, -+ RM_EV_busy_timer_expire, -+ RM_EV_delay_timer_expire, -+ RM_EV_meas_timer_expire, -+ RM_EV_retry_timer_expire, -+ RM_EV_repeat_delay_expire, -+ RM_EV_request_timer_expire, -+ RM_EV_wait_report, -+ RM_EV_start_meas, -+ RM_EV_survey_done, -+ RM_EV_recv_rep, -+ RM_EV_cancel, -+ RM_EV_state_out, -+ RM_EV_max -+}; -+ -+struct rm_event { -+ u32 rmid; -+ enum RM_EV_ID evid; -+ _list list; -+}; -+ -+#ifdef CONFIG_RTW_80211K -+ -+struct rm_clock { -+ struct rm_obj *prm; -+ ATOMIC_T counter; -+ enum RM_EV_ID evid; -+}; -+ -+struct rm_priv { -+ u8 enable; -+ _queue ev_queue; -+ _queue rm_queue; -+ _timer rm_timer; -+ -+ struct rm_clock clock[RM_TIMER_NUM]; -+ u8 rm_en_cap_def[5]; -+ u8 rm_en_cap_assoc[5]; -+ -+ /* rm debug */ -+ void *prm_sel; -+}; -+ -+int rtw_init_rm(_adapter *padapter); -+int rtw_free_rm_priv(_adapter *padapter); -+ -+unsigned int rm_on_action(_adapter *padapter, union recv_frame *precv_frame); -+void RM_IE_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE); -+void rtw_ap_parse_sta_rm_en_cap(_adapter *padapter, -+ struct sta_info *psta, struct rtw_ieee802_11_elems *elems); -+ -+int rm_post_event(_adapter *padapter, u32 rmid, enum RM_EV_ID evid); -+void rm_handler(_adapter *padapter, struct rm_event *pev); -+ -+u8 rm_add_nb_req(_adapter *padapter, struct sta_info *psta); -+ -+#endif /*CONFIG_RTW_80211K */ -+#endif /* __RTW_RM_H_ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_rm_fsm.h linux-5.8/3rdparty/rtl8812au/include/rtw_rm_fsm.h -new file mode 100644 -index 000000000..ba903a9c4 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_rm_fsm.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_rm_fsm.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_rm_fsm.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_rm_fsm.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_rm_fsm.h 2021-03-07 18:16:17.091957802 +0200 @@ -0,0 +1,389 @@ + +/****************************************************************************** @@ -409604,11 +405898,101 @@ index 000000000..ba903a9c4 + +#endif /*CONFIG_RTW_80211K*/ +#endif /*__RTW_RM_FSM_H_*/ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_rson.h linux-5.8/3rdparty/rtl8812au/include/rtw_rson.h -new file mode 100644 -index 000000000..6996738b0 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_rson.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_rm.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_rm.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_rm.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_rm.h 2021-03-07 18:16:17.091957802 +0200 +@@ -0,0 +1,88 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++ ++#ifndef __RTW_RM_H_ ++#define __RTW_RM_H_ ++ ++u8 rm_post_event_hdl(_adapter *padapter, u8 *pbuf); ++ ++#define RM_TIMER_NUM 32 ++#define RM_ALL_MEAS BIT(1) ++#define RM_ID_FOR_ALL(aid) ((aid<<16)|RM_ALL_MEAS) ++ ++#define RM_CAP_ARG(x) ((u8 *)(x))[4], ((u8 *)(x))[3], ((u8 *)(x))[2], ((u8 *)(x))[1], ((u8 *)(x))[0] ++#define RM_CAP_FMT "%02x %02x%02x %02x%02x" ++ ++/* remember to modify rm_event_name() when adding new event */ ++enum RM_EV_ID { ++ RM_EV_state_in, ++ RM_EV_busy_timer_expire, ++ RM_EV_delay_timer_expire, ++ RM_EV_meas_timer_expire, ++ RM_EV_retry_timer_expire, ++ RM_EV_repeat_delay_expire, ++ RM_EV_request_timer_expire, ++ RM_EV_wait_report, ++ RM_EV_start_meas, ++ RM_EV_survey_done, ++ RM_EV_recv_rep, ++ RM_EV_cancel, ++ RM_EV_state_out, ++ RM_EV_max ++}; ++ ++struct rm_event { ++ u32 rmid; ++ enum RM_EV_ID evid; ++ _list list; ++}; ++ ++#ifdef CONFIG_RTW_80211K ++ ++struct rm_clock { ++ struct rm_obj *prm; ++ ATOMIC_T counter; ++ enum RM_EV_ID evid; ++}; ++ ++struct rm_priv { ++ u8 enable; ++ _queue ev_queue; ++ _queue rm_queue; ++ _timer rm_timer; ++ ++ struct rm_clock clock[RM_TIMER_NUM]; ++ u8 rm_en_cap_def[5]; ++ u8 rm_en_cap_assoc[5]; ++ ++ /* rm debug */ ++ void *prm_sel; ++}; ++ ++int rtw_init_rm(_adapter *padapter); ++int rtw_free_rm_priv(_adapter *padapter); ++ ++unsigned int rm_on_action(_adapter *padapter, union recv_frame *precv_frame); ++void RM_IE_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE); ++void rtw_ap_parse_sta_rm_en_cap(_adapter *padapter, ++ struct sta_info *psta, struct rtw_ieee802_11_elems *elems); ++ ++int rm_post_event(_adapter *padapter, u32 rmid, enum RM_EV_ID evid); ++void rm_handler(_adapter *padapter, struct rm_event *pev); ++ ++u8 rm_add_nb_req(_adapter *padapter, struct sta_info *psta); ++ ++#endif /*CONFIG_RTW_80211K */ ++#endif /* __RTW_RM_H_ */ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_rson.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_rson.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_rson.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_rson.h 2021-03-07 18:16:17.091957802 +0200 @@ -0,0 +1,61 @@ +/****************************************************************************** + * @@ -409671,11 +406055,9 @@ index 000000000..6996738b0 +u8 rtw_rson_scan_wk_cmd(_adapter *padapter, int op); +void rtw_rson_scan_cmd_hdl(_adapter *padapter, int op); +#endif /* __RTW_RSON_H_ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_sdio.h linux-5.8/3rdparty/rtl8812au/include/rtw_sdio.h -new file mode 100644 -index 000000000..7490b5481 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_sdio.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_sdio.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_sdio.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_sdio.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_sdio.h 2021-03-07 18:16:17.091957802 +0200 @@ -0,0 +1,26 @@ +/****************************************************************************** + * @@ -409703,11 +406085,9 @@ index 000000000..7490b5481 +u8 rtw_sdio_f0_read(struct dvobj_priv *, u32 addr, void *buf, size_t len); + +#endif /* _RTW_SDIO_H_ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_security.h linux-5.8/3rdparty/rtl8812au/include/rtw_security.h -new file mode 100644 -index 000000000..f09f8a366 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_security.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_security.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_security.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_security.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_security.h 2021-03-07 18:16:17.091957802 +0200 @@ -0,0 +1,502 @@ +/****************************************************************************** + * @@ -410211,11 +406591,9 @@ index 000000000..f09f8a366 + ((a)->securitypriv.auth_type == (s)) + +#endif /* __RTL871X_SECURITY_H_ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_sreset.h linux-5.8/3rdparty/rtl8812au/include/rtw_sreset.h -new file mode 100644 -index 000000000..1fd999a9d ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_sreset.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_sreset.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_sreset.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_sreset.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_sreset.h 2021-03-07 18:16:17.091957802 +0200 @@ -0,0 +1,66 @@ +/****************************************************************************** + * @@ -410283,11 +406661,9 @@ index 000000000..1fd999a9d +void sreset_reset(_adapter *padapter); + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_tdls.h linux-5.8/3rdparty/rtl8812au/include/rtw_tdls.h -new file mode 100644 -index 000000000..5c23e4ea4 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_tdls.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_tdls.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_tdls.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_tdls.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_tdls.h 2021-03-07 18:16:17.091957802 +0200 @@ -0,0 +1,185 @@ +/****************************************************************************** + * @@ -410474,200 +406850,9 @@ index 000000000..5c23e4ea4 +#endif /* CONFIG_TDLS */ + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_version.h linux-5.8/3rdparty/rtl8812au/include/rtw_version.h -new file mode 100644 -index 000000000..d1591da8e ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_version.h -@@ -0,0 +1 @@ -+#define DRIVERVERSION "v5.6.4.2_35491.20191025" -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_vht.h linux-5.8/3rdparty/rtl8812au/include/rtw_vht.h -new file mode 100644 -index 000000000..88122224b ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_vht.h -@@ -0,0 +1,176 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+#ifndef _RTW_VHT_H_ -+#define _RTW_VHT_H_ -+ -+#define VHT_CAP_IE_LEN 12 -+#define VHT_OP_IE_LEN 5 -+ -+#define LDPC_VHT_ENABLE_RX BIT0 -+#define LDPC_VHT_ENABLE_TX BIT1 -+#define LDPC_VHT_TEST_TX_ENABLE BIT2 -+#define LDPC_VHT_CAP_TX BIT3 -+ -+#define STBC_VHT_ENABLE_RX BIT0 -+#define STBC_VHT_ENABLE_TX BIT1 -+#define STBC_VHT_TEST_TX_ENABLE BIT2 -+#define STBC_VHT_CAP_TX BIT3 -+ -+/* VHT capability info */ -+#define SET_VHT_CAPABILITY_ELE_MAX_MPDU_LENGTH(_pEleStart, _val) SET_BITS_TO_LE_1BYTE(_pEleStart, 0, 2, _val) -+#define SET_VHT_CAPABILITY_ELE_CHL_WIDTH(_pEleStart, _val) SET_BITS_TO_LE_1BYTE(_pEleStart, 2, 2, _val) -+#define SET_VHT_CAPABILITY_ELE_RX_LDPC(_pEleStart, _val) SET_BITS_TO_LE_1BYTE(_pEleStart, 4, 1, _val) -+#define SET_VHT_CAPABILITY_ELE_SHORT_GI80M(_pEleStart, _val) SET_BITS_TO_LE_1BYTE(_pEleStart, 5, 1, _val) -+#define SET_VHT_CAPABILITY_ELE_SHORT_GI160M(_pEleStart, _val) SET_BITS_TO_LE_1BYTE(_pEleStart, 6, 1, _val) -+#define SET_VHT_CAPABILITY_ELE_TX_STBC(_pEleStart, _val) SET_BITS_TO_LE_1BYTE(_pEleStart, 7, 1, _val) -+#define SET_VHT_CAPABILITY_ELE_RX_STBC(_pEleStart, _val) SET_BITS_TO_LE_1BYTE((_pEleStart)+1, 0, 3, _val) -+#define SET_VHT_CAPABILITY_ELE_SU_BFER(_pEleStart, _val) SET_BITS_TO_LE_1BYTE((_pEleStart)+1, 3, 1, _val) -+#define SET_VHT_CAPABILITY_ELE_SU_BFEE(_pEleStart, _val) SET_BITS_TO_LE_1BYTE((_pEleStart)+1, 4, 1, _val) -+#define SET_VHT_CAPABILITY_ELE_BFER_ANT_SUPP(_pEleStart, _val) SET_BITS_TO_LE_1BYTE((_pEleStart)+1, 5, 3, _val) -+#define SET_VHT_CAPABILITY_ELE_SOUNDING_DIMENSIONS(_pEleStart, _val) SET_BITS_TO_LE_1BYTE((_pEleStart)+2, 0, 3, _val) -+ -+#define SET_VHT_CAPABILITY_ELE_MU_BFER(_pEleStart, _val) SET_BITS_TO_LE_1BYTE((_pEleStart)+2, 3, 1, _val) -+#define SET_VHT_CAPABILITY_ELE_MU_BFEE(_pEleStart, _val) SET_BITS_TO_LE_1BYTE((_pEleStart)+2, 4, 1, _val) -+#define SET_VHT_CAPABILITY_ELE_TXOP_PS(_pEleStart, _val) SET_BITS_TO_LE_1BYTE((_pEleStart)+2, 5, 1, _val) -+#define SET_VHT_CAPABILITY_ELE_HTC_VHT(_pEleStart, _val) SET_BITS_TO_LE_1BYTE((_pEleStart)+2, 6, 1, _val) -+#define SET_VHT_CAPABILITY_ELE_MAX_RXAMPDU_FACTOR(_pEleStart, _val) SET_BITS_TO_LE_2BYTE((_pEleStart)+2, 7, 3, _val) /* B23~B25 */ -+#define SET_VHT_CAPABILITY_ELE_LINK_ADAPTION(_pEleStart, _val) SET_BITS_TO_LE_1BYTE((_pEleStart)+2, 2, 2, _val) -+#define SET_VHT_CAPABILITY_ELE_MCS_RX_MAP(_pEleStart, _val) SET_BITS_TO_LE_2BYTE((_pEleStart)+4, 0, 16, _val) /* B0~B15 indicate Rx MCS MAP, we write 0 to indicate MCS0~7. by page */ -+#define SET_VHT_CAPABILITY_ELE_MCS_RX_HIGHEST_RATE(_pEleStart, _val) SET_BITS_TO_LE_2BYTE((_pEleStart)+6, 0, 13, _val) -+#define SET_VHT_CAPABILITY_ELE_MCS_TX_MAP(_pEleStart, _val) SET_BITS_TO_LE_2BYTE((_pEleStart)+8, 0, 16, _val) /* B0~B15 indicate Tx MCS MAP, we write 0 to indicate MCS0~7. by page */ -+#define SET_VHT_CAPABILITY_ELE_MCS_TX_HIGHEST_RATE(_pEleStart, _val) SET_BITS_TO_LE_2BYTE((_pEleStart)+10, 0, 13, _val) -+ -+ -+#define GET_VHT_CAPABILITY_ELE_MAX_MPDU_LENGTH(_pEleStart) LE_BITS_TO_1BYTE(_pEleStart, 0, 2) -+#define GET_VHT_CAPABILITY_ELE_CHL_WIDTH(_pEleStart) LE_BITS_TO_1BYTE(_pEleStart, 2, 2) -+#define GET_VHT_CAPABILITY_ELE_RX_LDPC(_pEleStart) LE_BITS_TO_1BYTE(_pEleStart, 4, 1) -+#define GET_VHT_CAPABILITY_ELE_SHORT_GI80M(_pEleStart) LE_BITS_TO_1BYTE(_pEleStart, 5, 1) -+#define GET_VHT_CAPABILITY_ELE_SHORT_GI160M(_pEleStart) LE_BITS_TO_1BYTE(_pEleStart, 6, 1) -+#define GET_VHT_CAPABILITY_ELE_TX_STBC(_pEleStart) LE_BITS_TO_1BYTE(_pEleStart, 7, 1) -+#define GET_VHT_CAPABILITY_ELE_RX_STBC(_pEleStart) LE_BITS_TO_1BYTE((_pEleStart)+1, 0, 3) -+#define GET_VHT_CAPABILITY_ELE_SU_BFER(_pEleStart) LE_BITS_TO_1BYTE((_pEleStart)+1, 3, 1) -+#define GET_VHT_CAPABILITY_ELE_SU_BFEE(_pEleStart) LE_BITS_TO_1BYTE((_pEleStart)+1, 4, 1) -+/*phydm-beamforming*/ -+#define GET_VHT_CAPABILITY_ELE_SU_BFEE_STS_CAP(_pEleStart) LE_BITS_TO_2BYTE((_pEleStart)+1, 5, 3) -+#define GET_VHT_CAPABILITY_ELE_SU_BFER_SOUND_DIM_NUM(_pEleStart) LE_BITS_TO_2BYTE((_pEleStart)+2, 0, 3) -+#define GET_VHT_CAPABILITY_ELE_MU_BFER(_pEleStart) LE_BITS_TO_1BYTE((_pEleStart)+2, 3, 1) -+#define GET_VHT_CAPABILITY_ELE_MU_BFEE(_pEleStart) LE_BITS_TO_1BYTE((_pEleStart)+2, 4, 1) -+#define GET_VHT_CAPABILITY_ELE_TXOP_PS(_pEleStart) LE_BITS_TO_1BYTE((_pEleStart)+2, 5, 1) -+#define GET_VHT_CAPABILITY_ELE_MAX_RXAMPDU_FACTOR(_pEleStart) LE_BITS_TO_2BYTE((_pEleStart)+2, 7, 3) -+#define GET_VHT_CAPABILITY_ELE_RX_MCS(_pEleStart) ((_pEleStart)+4) -+#define GET_VHT_CAPABILITY_ELE_MCS_RX_HIGHEST_RATE(_pEleStart) LE_BITS_TO_2BYTE((_pEleStart)+6, 0, 13) -+#define GET_VHT_CAPABILITY_ELE_TX_MCS(_pEleStart) ((_pEleStart)+8) -+#define GET_VHT_CAPABILITY_ELE_MCS_TX_HIGHEST_RATE(_pEleStart) LE_BITS_TO_2BYTE((_pEleStart)+10, 0, 13) -+ -+ -+/* VHT Operation Information Element */ -+#define SET_VHT_OPERATION_ELE_CHL_WIDTH(_pEleStart, _val) SET_BITS_TO_LE_1BYTE(_pEleStart, 0, 8, _val) -+#define SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ1(_pEleStart, _val) SET_BITS_TO_LE_1BYTE(_pEleStart+1, 0, 8, _val) -+#define SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ2(_pEleStart, _val) SET_BITS_TO_LE_1BYTE(_pEleStart+2, 0, 8, _val) -+#define SET_VHT_OPERATION_ELE_BASIC_MCS_SET(_pEleStart, _val) SET_BITS_TO_LE_2BYTE((_pEleStart)+3, 0, 16, _val) -+ -+#define GET_VHT_OPERATION_ELE_CHL_WIDTH(_pEleStart) LE_BITS_TO_1BYTE(_pEleStart, 0, 8) -+#define GET_VHT_OPERATION_ELE_CENTER_FREQ1(_pEleStart) LE_BITS_TO_1BYTE((_pEleStart)+1, 0, 8) -+#define GET_VHT_OPERATION_ELE_CENTER_FREQ2(_pEleStart) LE_BITS_TO_1BYTE((_pEleStart)+2, 0, 8) -+ -+/* VHT Operating Mode */ -+#define SET_VHT_OPERATING_MODE_FIELD_CHNL_WIDTH(_pEleStart, _val) SET_BITS_TO_LE_1BYTE(_pEleStart, 0, 2, _val) -+#define SET_VHT_OPERATING_MODE_FIELD_RX_NSS(_pEleStart, _val) SET_BITS_TO_LE_1BYTE(_pEleStart, 4, 3, _val) -+#define SET_VHT_OPERATING_MODE_FIELD_RX_NSS_TYPE(_pEleStart, _val) SET_BITS_TO_LE_1BYTE(_pEleStart, 7, 1, _val) -+#define GET_VHT_OPERATING_MODE_FIELD_CHNL_WIDTH(_pEleStart) LE_BITS_TO_1BYTE(_pEleStart, 0, 2) -+#define GET_VHT_OPERATING_MODE_FIELD_RX_NSS(_pEleStart) LE_BITS_TO_1BYTE(_pEleStart, 4, 3) -+#define GET_VHT_OPERATING_MODE_FIELD_RX_NSS_TYPE(_pEleStart) LE_BITS_TO_1BYTE(_pEleStart, 7, 1) -+ -+#define SET_EXT_CAPABILITY_ELE_OP_MODE_NOTIF(_pEleStart, _val) SET_BITS_TO_LE_1BYTE((_pEleStart)+7, 6, 1, _val) -+#define GET_EXT_CAPABILITY_ELE_OP_MODE_NOTIF(_pEleStart) LE_BITS_TO_1BYTE((_pEleStart)+7, 6, 1) -+ -+#define VHT_MAX_MPDU_LEN_MAX 3 -+extern const u16 _vht_max_mpdu_len[]; -+#define vht_max_mpdu_len(val) (((val) >= VHT_MAX_MPDU_LEN_MAX) ? _vht_max_mpdu_len[VHT_MAX_MPDU_LEN_MAX] : _vht_max_mpdu_len[(val)]) -+ -+#define VHT_SUP_CH_WIDTH_SET_MAX 3 -+extern const u8 _vht_sup_ch_width_set_to_bw_cap[]; -+#define vht_sup_ch_width_set_to_bw_cap(set) (((set) >= VHT_SUP_CH_WIDTH_SET_MAX) ? _vht_sup_ch_width_set_to_bw_cap[VHT_SUP_CH_WIDTH_SET_MAX] : _vht_sup_ch_width_set_to_bw_cap[(set)]) -+extern const char *const _vht_sup_ch_width_set_str[]; -+#define vht_sup_ch_width_set_str(set) (((set) >= VHT_SUP_CH_WIDTH_SET_MAX) ? _vht_sup_ch_width_set_str[VHT_SUP_CH_WIDTH_SET_MAX] : _vht_sup_ch_width_set_str[(set)]) -+ -+#define VHT_MAX_AMPDU_LEN(f) ((1 << (13 + f)) - 1) -+void dump_vht_cap_ie(void *sel, const u8 *ie, u32 ie_len); -+ -+#define VHT_OP_CH_WIDTH_MAX 4 -+extern const char *const _vht_op_ch_width_str[]; -+#define vht_op_ch_width_str(ch_width) (((ch_width) >= VHT_OP_CH_WIDTH_MAX) ? _vht_op_ch_width_str[VHT_OP_CH_WIDTH_MAX] : _vht_op_ch_width_str[(ch_width)]) -+ -+void dump_vht_op_ie(void *sel, const u8 *ie, u32 ie_len); -+ -+struct vht_priv { -+ u8 vht_option; -+ -+ u8 ldpc_cap; -+ u8 stbc_cap; -+ u16 beamform_cap; -+ u8 ap_is_mu_bfer; -+ -+ u8 sgi_80m;/* short GI */ -+ u8 ampdu_len; -+ -+ u8 vht_highest_rate; -+ u8 vht_mcs_map[2]; -+ -+ u8 op_present:1; /* vht_op is present */ -+ u8 notify_present:1; /* vht_op_mode_notify is present */ -+ -+ u8 vht_cap[32]; -+ u8 vht_op[VHT_OP_IE_LEN]; -+ u8 vht_op_mode_notify; -+}; -+ -+#ifdef ROKU_PRIVATE -+struct vht_priv_infra_ap { -+ -+ /* Infra mode, only store for AP's info, not intersection of STA and AP*/ -+ u8 ldpc_cap_infra_ap; -+ u8 stbc_cap_infra_ap; -+ u16 beamform_cap_infra_ap; -+ u8 vht_mcs_map_infra_ap[2]; -+ u8 vht_mcs_map_tx_infra_ap[2]; -+ u8 channel_width_infra_ap; -+ u8 number_of_streams_infra_ap; -+}; -+#endif /* ROKU_PRIVATE */ -+ -+u8 rtw_get_vht_highest_rate(u8 *pvht_mcs_map); -+u16 rtw_vht_mcs_to_data_rate(u8 bw, u8 short_GI, u8 vht_mcs_rate); -+u64 rtw_vht_mcs_map_to_bitmap(u8 *mcs_map, u8 nss); -+void rtw_vht_use_default_setting(_adapter *padapter); -+u32 rtw_build_vht_operation_ie(_adapter *padapter, u8 *pbuf, u8 channel); -+u32 rtw_build_vht_op_mode_notify_ie(_adapter *padapter, u8 *pbuf, u8 bw); -+u32 rtw_build_vht_cap_ie(_adapter *padapter, u8 *pbuf); -+void update_sta_vht_info_apmode(_adapter *padapter, PVOID psta); -+void update_hw_vht_param(_adapter *padapter); -+void VHT_caps_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE); -+#ifdef ROKU_PRIVATE -+void VHT_caps_handler_infra_ap(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE); -+#endif /* ROKU_PRIVATE */ -+void VHT_operation_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE); -+void rtw_process_vht_op_mode_notify(_adapter *padapter, u8 *pframe, PVOID sta); -+u32 rtw_restructure_vht_ie(_adapter *padapter, u8 *in_ie, u8 *out_ie, uint in_len, uint *pout_len); -+void VHTOnAssocRsp(_adapter *padapter); -+u8 rtw_vht_mcsmap_to_nss(u8 *pvht_mcs_map); -+void rtw_vht_nss_to_mcsmap(u8 nss, u8 *target_mcs_map, u8 *cur_mcs_map); -+void rtw_vht_ies_attach(_adapter *padapter, WLAN_BSSID_EX *pcur_network); -+void rtw_vht_ies_detach(_adapter *padapter, WLAN_BSSID_EX *pcur_network); -+void rtw_check_for_vht20(_adapter *adapter, u8 *ies, int ies_len); -+#endif /* _RTW_VHT_H_ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_wapi.h linux-5.8/3rdparty/rtl8812au/include/rtw_wapi.h -new file mode 100644 -index 000000000..512bb7f30 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_wapi.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_wapi.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_wapi.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_wapi.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_wapi.h 2021-03-07 18:16:17.091957802 +0200 @@ -0,0 +1,230 @@ +/****************************************************************************** + * @@ -410899,11 +407084,194 @@ index 000000000..512bb7f30 +void rtw_wapi_set_set_encryption(_adapter *padapter, struct ieee_param *param); + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_wifi_regd.h linux-5.8/3rdparty/rtl8812au/include/rtw_wifi_regd.h -new file mode 100644 -index 000000000..8e42fce7a ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_wifi_regd.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_version.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_version.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_version.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_version.h 2021-03-07 18:16:17.091957802 +0200 +@@ -0,0 +1 @@ ++#define DRIVERVERSION "v5.6.4.2_35491.20191025" +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_vht.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_vht.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_vht.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_vht.h 2021-03-07 18:16:17.091957802 +0200 +@@ -0,0 +1,176 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++#ifndef _RTW_VHT_H_ ++#define _RTW_VHT_H_ ++ ++#define VHT_CAP_IE_LEN 12 ++#define VHT_OP_IE_LEN 5 ++ ++#define LDPC_VHT_ENABLE_RX BIT0 ++#define LDPC_VHT_ENABLE_TX BIT1 ++#define LDPC_VHT_TEST_TX_ENABLE BIT2 ++#define LDPC_VHT_CAP_TX BIT3 ++ ++#define STBC_VHT_ENABLE_RX BIT0 ++#define STBC_VHT_ENABLE_TX BIT1 ++#define STBC_VHT_TEST_TX_ENABLE BIT2 ++#define STBC_VHT_CAP_TX BIT3 ++ ++/* VHT capability info */ ++#define SET_VHT_CAPABILITY_ELE_MAX_MPDU_LENGTH(_pEleStart, _val) SET_BITS_TO_LE_1BYTE(_pEleStart, 0, 2, _val) ++#define SET_VHT_CAPABILITY_ELE_CHL_WIDTH(_pEleStart, _val) SET_BITS_TO_LE_1BYTE(_pEleStart, 2, 2, _val) ++#define SET_VHT_CAPABILITY_ELE_RX_LDPC(_pEleStart, _val) SET_BITS_TO_LE_1BYTE(_pEleStart, 4, 1, _val) ++#define SET_VHT_CAPABILITY_ELE_SHORT_GI80M(_pEleStart, _val) SET_BITS_TO_LE_1BYTE(_pEleStart, 5, 1, _val) ++#define SET_VHT_CAPABILITY_ELE_SHORT_GI160M(_pEleStart, _val) SET_BITS_TO_LE_1BYTE(_pEleStart, 6, 1, _val) ++#define SET_VHT_CAPABILITY_ELE_TX_STBC(_pEleStart, _val) SET_BITS_TO_LE_1BYTE(_pEleStart, 7, 1, _val) ++#define SET_VHT_CAPABILITY_ELE_RX_STBC(_pEleStart, _val) SET_BITS_TO_LE_1BYTE((_pEleStart)+1, 0, 3, _val) ++#define SET_VHT_CAPABILITY_ELE_SU_BFER(_pEleStart, _val) SET_BITS_TO_LE_1BYTE((_pEleStart)+1, 3, 1, _val) ++#define SET_VHT_CAPABILITY_ELE_SU_BFEE(_pEleStart, _val) SET_BITS_TO_LE_1BYTE((_pEleStart)+1, 4, 1, _val) ++#define SET_VHT_CAPABILITY_ELE_BFER_ANT_SUPP(_pEleStart, _val) SET_BITS_TO_LE_1BYTE((_pEleStart)+1, 5, 3, _val) ++#define SET_VHT_CAPABILITY_ELE_SOUNDING_DIMENSIONS(_pEleStart, _val) SET_BITS_TO_LE_1BYTE((_pEleStart)+2, 0, 3, _val) ++ ++#define SET_VHT_CAPABILITY_ELE_MU_BFER(_pEleStart, _val) SET_BITS_TO_LE_1BYTE((_pEleStart)+2, 3, 1, _val) ++#define SET_VHT_CAPABILITY_ELE_MU_BFEE(_pEleStart, _val) SET_BITS_TO_LE_1BYTE((_pEleStart)+2, 4, 1, _val) ++#define SET_VHT_CAPABILITY_ELE_TXOP_PS(_pEleStart, _val) SET_BITS_TO_LE_1BYTE((_pEleStart)+2, 5, 1, _val) ++#define SET_VHT_CAPABILITY_ELE_HTC_VHT(_pEleStart, _val) SET_BITS_TO_LE_1BYTE((_pEleStart)+2, 6, 1, _val) ++#define SET_VHT_CAPABILITY_ELE_MAX_RXAMPDU_FACTOR(_pEleStart, _val) SET_BITS_TO_LE_2BYTE((_pEleStart)+2, 7, 3, _val) /* B23~B25 */ ++#define SET_VHT_CAPABILITY_ELE_LINK_ADAPTION(_pEleStart, _val) SET_BITS_TO_LE_1BYTE((_pEleStart)+2, 2, 2, _val) ++#define SET_VHT_CAPABILITY_ELE_MCS_RX_MAP(_pEleStart, _val) SET_BITS_TO_LE_2BYTE((_pEleStart)+4, 0, 16, _val) /* B0~B15 indicate Rx MCS MAP, we write 0 to indicate MCS0~7. by page */ ++#define SET_VHT_CAPABILITY_ELE_MCS_RX_HIGHEST_RATE(_pEleStart, _val) SET_BITS_TO_LE_2BYTE((_pEleStart)+6, 0, 13, _val) ++#define SET_VHT_CAPABILITY_ELE_MCS_TX_MAP(_pEleStart, _val) SET_BITS_TO_LE_2BYTE((_pEleStart)+8, 0, 16, _val) /* B0~B15 indicate Tx MCS MAP, we write 0 to indicate MCS0~7. by page */ ++#define SET_VHT_CAPABILITY_ELE_MCS_TX_HIGHEST_RATE(_pEleStart, _val) SET_BITS_TO_LE_2BYTE((_pEleStart)+10, 0, 13, _val) ++ ++ ++#define GET_VHT_CAPABILITY_ELE_MAX_MPDU_LENGTH(_pEleStart) LE_BITS_TO_1BYTE(_pEleStart, 0, 2) ++#define GET_VHT_CAPABILITY_ELE_CHL_WIDTH(_pEleStart) LE_BITS_TO_1BYTE(_pEleStart, 2, 2) ++#define GET_VHT_CAPABILITY_ELE_RX_LDPC(_pEleStart) LE_BITS_TO_1BYTE(_pEleStart, 4, 1) ++#define GET_VHT_CAPABILITY_ELE_SHORT_GI80M(_pEleStart) LE_BITS_TO_1BYTE(_pEleStart, 5, 1) ++#define GET_VHT_CAPABILITY_ELE_SHORT_GI160M(_pEleStart) LE_BITS_TO_1BYTE(_pEleStart, 6, 1) ++#define GET_VHT_CAPABILITY_ELE_TX_STBC(_pEleStart) LE_BITS_TO_1BYTE(_pEleStart, 7, 1) ++#define GET_VHT_CAPABILITY_ELE_RX_STBC(_pEleStart) LE_BITS_TO_1BYTE((_pEleStart)+1, 0, 3) ++#define GET_VHT_CAPABILITY_ELE_SU_BFER(_pEleStart) LE_BITS_TO_1BYTE((_pEleStart)+1, 3, 1) ++#define GET_VHT_CAPABILITY_ELE_SU_BFEE(_pEleStart) LE_BITS_TO_1BYTE((_pEleStart)+1, 4, 1) ++/*phydm-beamforming*/ ++#define GET_VHT_CAPABILITY_ELE_SU_BFEE_STS_CAP(_pEleStart) LE_BITS_TO_2BYTE((_pEleStart)+1, 5, 3) ++#define GET_VHT_CAPABILITY_ELE_SU_BFER_SOUND_DIM_NUM(_pEleStart) LE_BITS_TO_2BYTE((_pEleStart)+2, 0, 3) ++#define GET_VHT_CAPABILITY_ELE_MU_BFER(_pEleStart) LE_BITS_TO_1BYTE((_pEleStart)+2, 3, 1) ++#define GET_VHT_CAPABILITY_ELE_MU_BFEE(_pEleStart) LE_BITS_TO_1BYTE((_pEleStart)+2, 4, 1) ++#define GET_VHT_CAPABILITY_ELE_TXOP_PS(_pEleStart) LE_BITS_TO_1BYTE((_pEleStart)+2, 5, 1) ++#define GET_VHT_CAPABILITY_ELE_MAX_RXAMPDU_FACTOR(_pEleStart) LE_BITS_TO_2BYTE((_pEleStart)+2, 7, 3) ++#define GET_VHT_CAPABILITY_ELE_RX_MCS(_pEleStart) ((_pEleStart)+4) ++#define GET_VHT_CAPABILITY_ELE_MCS_RX_HIGHEST_RATE(_pEleStart) LE_BITS_TO_2BYTE((_pEleStart)+6, 0, 13) ++#define GET_VHT_CAPABILITY_ELE_TX_MCS(_pEleStart) ((_pEleStart)+8) ++#define GET_VHT_CAPABILITY_ELE_MCS_TX_HIGHEST_RATE(_pEleStart) LE_BITS_TO_2BYTE((_pEleStart)+10, 0, 13) ++ ++ ++/* VHT Operation Information Element */ ++#define SET_VHT_OPERATION_ELE_CHL_WIDTH(_pEleStart, _val) SET_BITS_TO_LE_1BYTE(_pEleStart, 0, 8, _val) ++#define SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ1(_pEleStart, _val) SET_BITS_TO_LE_1BYTE(_pEleStart+1, 0, 8, _val) ++#define SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ2(_pEleStart, _val) SET_BITS_TO_LE_1BYTE(_pEleStart+2, 0, 8, _val) ++#define SET_VHT_OPERATION_ELE_BASIC_MCS_SET(_pEleStart, _val) SET_BITS_TO_LE_2BYTE((_pEleStart)+3, 0, 16, _val) ++ ++#define GET_VHT_OPERATION_ELE_CHL_WIDTH(_pEleStart) LE_BITS_TO_1BYTE(_pEleStart, 0, 8) ++#define GET_VHT_OPERATION_ELE_CENTER_FREQ1(_pEleStart) LE_BITS_TO_1BYTE((_pEleStart)+1, 0, 8) ++#define GET_VHT_OPERATION_ELE_CENTER_FREQ2(_pEleStart) LE_BITS_TO_1BYTE((_pEleStart)+2, 0, 8) ++ ++/* VHT Operating Mode */ ++#define SET_VHT_OPERATING_MODE_FIELD_CHNL_WIDTH(_pEleStart, _val) SET_BITS_TO_LE_1BYTE(_pEleStart, 0, 2, _val) ++#define SET_VHT_OPERATING_MODE_FIELD_RX_NSS(_pEleStart, _val) SET_BITS_TO_LE_1BYTE(_pEleStart, 4, 3, _val) ++#define SET_VHT_OPERATING_MODE_FIELD_RX_NSS_TYPE(_pEleStart, _val) SET_BITS_TO_LE_1BYTE(_pEleStart, 7, 1, _val) ++#define GET_VHT_OPERATING_MODE_FIELD_CHNL_WIDTH(_pEleStart) LE_BITS_TO_1BYTE(_pEleStart, 0, 2) ++#define GET_VHT_OPERATING_MODE_FIELD_RX_NSS(_pEleStart) LE_BITS_TO_1BYTE(_pEleStart, 4, 3) ++#define GET_VHT_OPERATING_MODE_FIELD_RX_NSS_TYPE(_pEleStart) LE_BITS_TO_1BYTE(_pEleStart, 7, 1) ++ ++#define SET_EXT_CAPABILITY_ELE_OP_MODE_NOTIF(_pEleStart, _val) SET_BITS_TO_LE_1BYTE((_pEleStart)+7, 6, 1, _val) ++#define GET_EXT_CAPABILITY_ELE_OP_MODE_NOTIF(_pEleStart) LE_BITS_TO_1BYTE((_pEleStart)+7, 6, 1) ++ ++#define VHT_MAX_MPDU_LEN_MAX 3 ++extern const u16 _vht_max_mpdu_len[]; ++#define vht_max_mpdu_len(val) (((val) >= VHT_MAX_MPDU_LEN_MAX) ? _vht_max_mpdu_len[VHT_MAX_MPDU_LEN_MAX] : _vht_max_mpdu_len[(val)]) ++ ++#define VHT_SUP_CH_WIDTH_SET_MAX 3 ++extern const u8 _vht_sup_ch_width_set_to_bw_cap[]; ++#define vht_sup_ch_width_set_to_bw_cap(set) (((set) >= VHT_SUP_CH_WIDTH_SET_MAX) ? _vht_sup_ch_width_set_to_bw_cap[VHT_SUP_CH_WIDTH_SET_MAX] : _vht_sup_ch_width_set_to_bw_cap[(set)]) ++extern const char *const _vht_sup_ch_width_set_str[]; ++#define vht_sup_ch_width_set_str(set) (((set) >= VHT_SUP_CH_WIDTH_SET_MAX) ? _vht_sup_ch_width_set_str[VHT_SUP_CH_WIDTH_SET_MAX] : _vht_sup_ch_width_set_str[(set)]) ++ ++#define VHT_MAX_AMPDU_LEN(f) ((1 << (13 + f)) - 1) ++void dump_vht_cap_ie(void *sel, const u8 *ie, u32 ie_len); ++ ++#define VHT_OP_CH_WIDTH_MAX 4 ++extern const char *const _vht_op_ch_width_str[]; ++#define vht_op_ch_width_str(ch_width) (((ch_width) >= VHT_OP_CH_WIDTH_MAX) ? _vht_op_ch_width_str[VHT_OP_CH_WIDTH_MAX] : _vht_op_ch_width_str[(ch_width)]) ++ ++void dump_vht_op_ie(void *sel, const u8 *ie, u32 ie_len); ++ ++struct vht_priv { ++ u8 vht_option; ++ ++ u8 ldpc_cap; ++ u8 stbc_cap; ++ u16 beamform_cap; ++ u8 ap_is_mu_bfer; ++ ++ u8 sgi_80m;/* short GI */ ++ u8 ampdu_len; ++ ++ u8 vht_highest_rate; ++ u8 vht_mcs_map[2]; ++ ++ u8 op_present:1; /* vht_op is present */ ++ u8 notify_present:1; /* vht_op_mode_notify is present */ ++ ++ u8 vht_cap[32]; ++ u8 vht_op[VHT_OP_IE_LEN]; ++ u8 vht_op_mode_notify; ++}; ++ ++#ifdef ROKU_PRIVATE ++struct vht_priv_infra_ap { ++ ++ /* Infra mode, only store for AP's info, not intersection of STA and AP*/ ++ u8 ldpc_cap_infra_ap; ++ u8 stbc_cap_infra_ap; ++ u16 beamform_cap_infra_ap; ++ u8 vht_mcs_map_infra_ap[2]; ++ u8 vht_mcs_map_tx_infra_ap[2]; ++ u8 channel_width_infra_ap; ++ u8 number_of_streams_infra_ap; ++}; ++#endif /* ROKU_PRIVATE */ ++ ++u8 rtw_get_vht_highest_rate(u8 *pvht_mcs_map); ++u16 rtw_vht_mcs_to_data_rate(u8 bw, u8 short_GI, u8 vht_mcs_rate); ++u64 rtw_vht_mcs_map_to_bitmap(u8 *mcs_map, u8 nss); ++void rtw_vht_use_default_setting(_adapter *padapter); ++u32 rtw_build_vht_operation_ie(_adapter *padapter, u8 *pbuf, u8 channel); ++u32 rtw_build_vht_op_mode_notify_ie(_adapter *padapter, u8 *pbuf, u8 bw); ++u32 rtw_build_vht_cap_ie(_adapter *padapter, u8 *pbuf); ++void update_sta_vht_info_apmode(_adapter *padapter, PVOID psta); ++void update_hw_vht_param(_adapter *padapter); ++void VHT_caps_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE); ++#ifdef ROKU_PRIVATE ++void VHT_caps_handler_infra_ap(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE); ++#endif /* ROKU_PRIVATE */ ++void VHT_operation_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE); ++void rtw_process_vht_op_mode_notify(_adapter *padapter, u8 *pframe, PVOID sta); ++u32 rtw_restructure_vht_ie(_adapter *padapter, u8 *in_ie, u8 *out_ie, uint in_len, uint *pout_len); ++void VHTOnAssocRsp(_adapter *padapter); ++u8 rtw_vht_mcsmap_to_nss(u8 *pvht_mcs_map); ++void rtw_vht_nss_to_mcsmap(u8 nss, u8 *target_mcs_map, u8 *cur_mcs_map); ++void rtw_vht_ies_attach(_adapter *padapter, WLAN_BSSID_EX *pcur_network); ++void rtw_vht_ies_detach(_adapter *padapter, WLAN_BSSID_EX *pcur_network); ++void rtw_check_for_vht20(_adapter *adapter, u8 *ies, int ies_len); ++#endif /* _RTW_VHT_H_ */ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_wifi_regd.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_wifi_regd.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_wifi_regd.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_wifi_regd.h 2021-03-07 18:16:17.091957802 +0200 @@ -0,0 +1,34 @@ +/****************************************************************************** + * @@ -410939,11 +407307,9 @@ index 000000000..8e42fce7a +int rtw_regd_init(struct wiphy *wiphy); + +#endif /* __RTW_WIFI_REGD_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/rtw_xmit.h linux-5.8/3rdparty/rtl8812au/include/rtw_xmit.h -new file mode 100644 -index 000000000..c1cd9286c ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/rtw_xmit.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_xmit.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_xmit.h +--- linux-5.11.4/3rdparty/rtl8812au/include/rtw_xmit.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/rtw_xmit.h 2021-03-07 18:16:17.091957802 +0200 @@ -0,0 +1,1072 @@ +/****************************************************************************** + * @@ -412017,11 +408383,9 @@ index 000000000..c1cd9286c +#include + +#endif /* _RTL871X_XMIT_H_ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/sdio_hal.h linux-5.8/3rdparty/rtl8812au/include/sdio_hal.h -new file mode 100644 -index 000000000..6e49835a4 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/sdio_hal.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/sdio_hal.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/sdio_hal.h +--- linux-5.11.4/3rdparty/rtl8812au/include/sdio_hal.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/sdio_hal.h 2021-03-07 18:16:17.092957849 +0200 @@ -0,0 +1,57 @@ +/****************************************************************************** + * @@ -412080,11 +408444,62 @@ index 000000000..6e49835a4 +#endif + +#endif /* __SDIO_HAL_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/sdio_ops.h linux-5.8/3rdparty/rtl8812au/include/sdio_ops.h -new file mode 100644 -index 000000000..613613de9 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/sdio_ops.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/sdio_ops_ce.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/sdio_ops_ce.h +--- linux-5.11.4/3rdparty/rtl8812au/include/sdio_ops_ce.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/sdio_ops_ce.h 2021-03-07 18:16:17.092957849 +0200 +@@ -0,0 +1,49 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++#ifndef _SDIO_OPS_WINCE_H_ ++#define _SDIO_OPS_WINCE_H_ ++ ++#include ++#include ++#include ++#include ++ ++ ++#ifdef PLATFORM_OS_CE ++ ++ ++extern u8 sdbus_cmd52r_ce(struct intf_priv *pintfpriv, u32 addr); ++ ++ ++extern void sdbus_cmd52w_ce(struct intf_priv *pintfpriv, u32 addr, u8 val8); ++ ++ ++uint sdbus_read_blocks_to_membuf_ce(struct intf_priv *pintfpriv, u32 addr, u32 cnt, u8 *pbuf); ++ ++extern uint sdbus_read_bytes_to_membuf_ce(struct intf_priv *pintfpriv, u32 addr, u32 cnt, u8 *pbuf); ++ ++ ++extern uint sdbus_write_blocks_from_membuf_ce(struct intf_priv *pintfpriv, u32 addr, u32 cnt, u8 *pbuf, u8 async); ++ ++extern uint sdbus_write_bytes_from_membuf_ce(struct intf_priv *pintfpriv, u32 addr, u32 cnt, u8 *pbuf); ++extern u8 sdbus_func1cmd52r_ce(struct intf_priv *pintfpriv, u32 addr); ++extern void sdbus_func1cmd52w_ce(struct intf_priv *pintfpriv, u32 addr, u8 val8); ++extern uint sdbus_read_reg(struct intf_priv *pintfpriv, u32 addr, u32 cnt, void *pdata); ++extern uint sdbus_write_reg(struct intf_priv *pintfpriv, u32 addr, u32 cnt, void *pdata); ++extern void sdio_read_int(_adapter *padapter, u32 addr, u8 sz, void *pdata); ++ ++#endif ++ ++#endif +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/sdio_ops.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/sdio_ops.h +--- linux-5.11.4/3rdparty/rtl8812au/include/sdio_ops.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/sdio_ops.h 2021-03-07 18:16:17.092957849 +0200 @@ -0,0 +1,224 @@ +/****************************************************************************** + * @@ -412310,66 +408725,9 @@ index 000000000..613613de9 +} + +#endif /* !__SDIO_OPS_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/sdio_ops_ce.h linux-5.8/3rdparty/rtl8812au/include/sdio_ops_ce.h -new file mode 100644 -index 000000000..d542cb7ea ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/sdio_ops_ce.h -@@ -0,0 +1,49 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+#ifndef _SDIO_OPS_WINCE_H_ -+#define _SDIO_OPS_WINCE_H_ -+ -+#include -+#include -+#include -+#include -+ -+ -+#ifdef PLATFORM_OS_CE -+ -+ -+extern u8 sdbus_cmd52r_ce(struct intf_priv *pintfpriv, u32 addr); -+ -+ -+extern void sdbus_cmd52w_ce(struct intf_priv *pintfpriv, u32 addr, u8 val8); -+ -+ -+uint sdbus_read_blocks_to_membuf_ce(struct intf_priv *pintfpriv, u32 addr, u32 cnt, u8 *pbuf); -+ -+extern uint sdbus_read_bytes_to_membuf_ce(struct intf_priv *pintfpriv, u32 addr, u32 cnt, u8 *pbuf); -+ -+ -+extern uint sdbus_write_blocks_from_membuf_ce(struct intf_priv *pintfpriv, u32 addr, u32 cnt, u8 *pbuf, u8 async); -+ -+extern uint sdbus_write_bytes_from_membuf_ce(struct intf_priv *pintfpriv, u32 addr, u32 cnt, u8 *pbuf); -+extern u8 sdbus_func1cmd52r_ce(struct intf_priv *pintfpriv, u32 addr); -+extern void sdbus_func1cmd52w_ce(struct intf_priv *pintfpriv, u32 addr, u8 val8); -+extern uint sdbus_read_reg(struct intf_priv *pintfpriv, u32 addr, u32 cnt, void *pdata); -+extern uint sdbus_write_reg(struct intf_priv *pintfpriv, u32 addr, u32 cnt, void *pdata); -+extern void sdio_read_int(_adapter *padapter, u32 addr, u8 sz, void *pdata); -+ -+#endif -+ -+#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/sdio_ops_linux.h linux-5.8/3rdparty/rtl8812au/include/sdio_ops_linux.h -new file mode 100644 -index 000000000..4bbd8fe7f ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/sdio_ops_linux.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/sdio_ops_linux.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/sdio_ops_linux.h +--- linux-5.11.4/3rdparty/rtl8812au/include/sdio_ops_linux.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/sdio_ops_linux.h 2021-03-07 18:16:17.092957849 +0200 @@ -0,0 +1,58 @@ +/****************************************************************************** + * @@ -412429,11 +408787,9 @@ index 000000000..4bbd8fe7f + +#endif /* __SDIO_OPS_LINUX_H__ */ + -diff --git linux-5.8/3rdparty/rtl8812au/include/sdio_ops_xp.h linux-5.8/3rdparty/rtl8812au/include/sdio_ops_xp.h -new file mode 100644 -index 000000000..d3d8764d3 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/sdio_ops_xp.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/sdio_ops_xp.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/sdio_ops_xp.h +--- linux-5.11.4/3rdparty/rtl8812au/include/sdio_ops_xp.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/sdio_ops_xp.h 2021-03-07 18:16:17.092957849 +0200 @@ -0,0 +1,49 @@ +/****************************************************************************** + * @@ -412484,11 +408840,9 @@ index 000000000..d3d8764d3 +#endif + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/sdio_osintf.h linux-5.8/3rdparty/rtl8812au/include/sdio_osintf.h -new file mode 100644 -index 000000000..7c2abd14d ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/sdio_osintf.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/sdio_osintf.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/sdio_osintf.h +--- linux-5.11.4/3rdparty/rtl8812au/include/sdio_osintf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/sdio_osintf.h 2021-03-07 18:16:17.092957849 +0200 @@ -0,0 +1,25 @@ +/****************************************************************************** + * @@ -412515,11 +408869,9 @@ index 000000000..7c2abd14d +#endif + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/sta_info.h linux-5.8/3rdparty/rtl8812au/include/sta_info.h -new file mode 100644 -index 000000000..762933a2c ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/sta_info.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/sta_info.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/sta_info.h +--- linux-5.11.4/3rdparty/rtl8812au/include/sta_info.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/sta_info.h 2021-03-07 18:16:17.092957849 +0200 @@ -0,0 +1,748 @@ +/****************************************************************************** + * @@ -413269,11 +409621,9 @@ index 000000000..762933a2c +#endif /* CONFIG_RTW_PRE_LINK_STA */ + +#endif /* _STA_INFO_H_ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/usb_hal.h linux-5.8/3rdparty/rtl8812au/include/usb_hal.h -new file mode 100644 -index 000000000..0074d3fc4 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/usb_hal.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/usb_hal.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/usb_hal.h +--- linux-5.11.4/3rdparty/rtl8812au/include/usb_hal.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/usb_hal.h 2021-03-07 18:16:17.092957849 +0200 @@ -0,0 +1,74 @@ +/****************************************************************************** + * @@ -413349,11 +409699,9 @@ index 000000000..0074d3fc4 +extern _adapter *rtw_usb_get_sw_pointer(void); +#endif /* CONFIG_INTEL_PROXIM */ +#endif /* __USB_HAL_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/usb_ops.h linux-5.8/3rdparty/rtl8812au/include/usb_ops.h -new file mode 100644 -index 000000000..6d5435d65 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/usb_ops.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/usb_ops.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/usb_ops.h +--- linux-5.11.4/3rdparty/rtl8812au/include/usb_ops.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/usb_ops.h 2021-03-07 18:16:17.092957849 +0200 @@ -0,0 +1,153 @@ +/****************************************************************************** + * @@ -413508,11 +409856,9 @@ index 000000000..6d5435d65 + + +#endif /* __USB_OPS_H_ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/usb_ops_linux.h linux-5.8/3rdparty/rtl8812au/include/usb_ops_linux.h -new file mode 100644 -index 000000000..bf59ca0fa ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/usb_ops_linux.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/usb_ops_linux.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/usb_ops_linux.h +--- linux-5.11.4/3rdparty/rtl8812au/include/usb_ops_linux.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/usb_ops_linux.h 2021-03-07 18:16:17.092957849 +0200 @@ -0,0 +1,98 @@ +/****************************************************************************** + * @@ -413612,11 +409958,9 @@ index 000000000..bf59ca0fa +u32 usb_read_interrupt(struct intf_hdl *pintfhdl, u32 addr); +#endif +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/usb_osintf.h linux-5.8/3rdparty/rtl8812au/include/usb_osintf.h -new file mode 100644 -index 000000000..7e5feed17 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/usb_osintf.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/usb_osintf.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/usb_osintf.h +--- linux-5.11.4/3rdparty/rtl8812au/include/usb_osintf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/usb_osintf.h 2021-03-07 18:16:17.092957849 +0200 @@ -0,0 +1,26 @@ +/****************************************************************************** + * @@ -413644,11 +409988,9 @@ index 000000000..7e5feed17 + + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/usb_vendor_req.h linux-5.8/3rdparty/rtl8812au/include/usb_vendor_req.h -new file mode 100644 -index 000000000..a003bfb8c ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/usb_vendor_req.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/usb_vendor_req.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/usb_vendor_req.h +--- linux-5.11.4/3rdparty/rtl8812au/include/usb_vendor_req.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/usb_vendor_req.h 2021-03-07 18:16:17.092957849 +0200 @@ -0,0 +1,56 @@ +/****************************************************************************** + * @@ -413706,11 +410048,9 @@ index 000000000..a003bfb8c +#endif + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/include/wifi.h linux-5.8/3rdparty/rtl8812au/include/wifi.h -new file mode 100644 -index 000000000..f071dd044 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/wifi.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/wifi.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/wifi.h +--- linux-5.11.4/3rdparty/rtl8812au/include/wifi.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/wifi.h 2021-03-07 18:16:17.092957849 +0200 @@ -0,0 +1,1419 @@ +/****************************************************************************** + * @@ -415131,11 +411471,9 @@ index 000000000..f071dd044 +#endif + +#endif /* _WIFI_H_ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/wlan_bssdef.h linux-5.8/3rdparty/rtl8812au/include/wlan_bssdef.h -new file mode 100644 -index 000000000..167ae7f9c ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/wlan_bssdef.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/wlan_bssdef.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/wlan_bssdef.h +--- linux-5.11.4/3rdparty/rtl8812au/include/wlan_bssdef.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/wlan_bssdef.h 2021-03-07 18:16:17.092957849 +0200 @@ -0,0 +1,704 @@ +/****************************************************************************** + * @@ -415841,11 +412179,9 @@ index 000000000..167ae7f9c + + +#endif /* #ifndef WLAN_BSSDEF_H_ */ -diff --git linux-5.8/3rdparty/rtl8812au/include/xmit_osdep.h linux-5.8/3rdparty/rtl8812au/include/xmit_osdep.h -new file mode 100644 -index 000000000..70070a890 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/include/xmit_osdep.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/xmit_osdep.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/xmit_osdep.h +--- linux-5.11.4/3rdparty/rtl8812au/include/xmit_osdep.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/include/xmit_osdep.h 2021-03-07 18:16:17.092957849 +0200 @@ -0,0 +1,94 @@ +/****************************************************************************** + * @@ -415941,11 +412277,2351 @@ index 000000000..70070a890 +void dump_os_queue(void *sel, _adapter *padapter); + +#endif /* __XMIT_OSDEP_H_ */ -diff --git linux-5.8/3rdparty/rtl8812au/os_dep/linux/custom_gpio_linux.c linux-5.8/3rdparty/rtl8812au/os_dep/linux/custom_gpio_linux.c -new file mode 100644 -index 000000000..23401b7d6 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/os_dep/linux/custom_gpio_linux.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/Kconfig linux-5.11.4-rtl8812au/3rdparty/rtl8812au/Kconfig +--- linux-5.11.4/3rdparty/rtl8812au/Kconfig 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/Kconfig 2021-03-07 18:16:16.978952460 +0200 +@@ -0,0 +1,6 @@ ++config 88XXAU ++ tristate "Realtek 88XXau USB WiFi" ++ depends on USB ++ help ++ Help message of 88XXau ++ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/Makefile linux-5.11.4-rtl8812au/3rdparty/rtl8812au/Makefile +--- linux-5.11.4/3rdparty/rtl8812au/Makefile 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/Makefile 2021-03-07 18:16:16.978952460 +0200 +@@ -0,0 +1,2328 @@ ++EXTRA_CFLAGS += $(USER_EXTRA_CFLAGS) -fno-pie ++EXTRA_CFLAGS += -O3 ++EXTRA_CFLAGS += -Wno-unused-variable ++#EXTRA_CFLAGS += -Wno-unused-value ++EXTRA_CFLAGS += -Wno-unused-label ++#EXTRA_CFLAGS += -Wno-unused-parameter ++EXTRA_CFLAGS += -Wno-unused-function ++EXTRA_CFLAGS += -Wimplicit-fallthrough=0 ++#EXTRA_CFLAGS += -Wno-parentheses-equality ++#EXTRA_CFLAGS += -Wno-pointer-bool-conversion ++EXTRA_CFLAGS += -Wno-unknown-pragmas ++#EXTRA_CFLAGS += -Wno-unused ++EXTRA_CFLAGS += -Wno-vla -g ++ ++#GCC_VER_49 := $(shell echo `$(CC) -dumpversion | cut -f1-2 -d.` \>= 4.9 | bc ) ++#ifeq ($(GCC_VER_49),1) ++#EXTRA_CFLAGS += -Wno-date-time # Fix compile error && warning on gcc 4.9 and later ++#endif ++ ++EXTRA_CFLAGS += -I$(src)/include ++EXTRA_LDFLAGS += --strip-all -O3 ++ ++########################## WIFI IC ############################ ++CONFIG_RTL8812A = y ++CONFIG_RTL8821A = y ++CONFIG_RTL8814A = n ++######################### Interface ########################### ++CONFIG_USB_HCI = y ++########################### Android ########################### ++CONFIG_SIGNAL_DISPLAY_DBM = y ++########################## Features ########################### ++CONFIG_NET_NS = y ++CONFIG_MP_INCLUDED = y ++CONFIG_POWER_SAVING = n ++CONFIG_USB_AUTOSUSPEND = n ++CONFIG_HW_PWRP_DETECTION = n ++CONFIG_BT_COEXIST = n ++CONFIG_INTEL_WIDI = n ++CONFIG_WAPI_SUPPORT = n ++CONFIG_EFUSE_CONFIG_FILE = y ++CONFIG_EXT_CLK = n ++CONFIG_TRAFFIC_PROTECT = n ++CONFIG_LOAD_PHY_PARA_FROM_FILE = y ++CONFIG_TXPWR_BY_RATE = y ++CONFIG_TXPWR_BY_RATE_EN = n ++CONFIG_TXPWR_LIMIT = y ++CONFIG_TXPWR_LIMIT_EN = n ++CONFIG_RTW_CHPLAN = 0xFF ++CONFIG_RTW_ADAPTIVITY_EN = disable ++CONFIG_RTW_ADAPTIVITY_MODE = normal ++CONFIG_SIGNAL_SCALE_MAPPING = n ++CONFIG_80211W = y ++CONFIG_REDUCE_TX_CPU_LOADING = n ++CONFIG_BR_EXT = y ++CONFIG_TDLS = n ++CONFIG_WIFI_MONITOR = y ++CONFIG_DISABLE_REGD_C = y ++CONFIG_MCC_MODE = n ++CONFIG_APPEND_VENDOR_IE_ENABLE = n ++CONFIG_RTW_NAPI = y ++CONFIG_RTW_GRO = y ++CONFIG_RTW_NETIF_SG = y ++CONFIG_TX_CSUM_OFFLOAD = n ++CONFIG_RTW_IPCAM_APPLICATION = n ++CONFIG_RTW_REPEATER_SON = n ++CONFIG_RTW_WIFI_HAL = n ++CONFIG_ICMP_VOQ = n ++CONFIG_IP_R_MONITOR = n #arp VOQ and high rate ++########################## Debug ########################### ++CONFIG_RTW_DEBUG = n ++# default log level is _DRV_INFO_ = 4, ++# please refer to "How_to_set_driver_debug_log_level.doc" to set the available level. ++CONFIG_RTW_LOG_LEVEL = 2 ++######################## Wake On Lan ########################## ++CONFIG_WOWLAN = n ++#bit2: deauth, bit1: unicast, bit0: magic pkt. ++CONFIG_WAKEUP_TYPE = 0x7 ++#bit0: disBBRF off, #bit1: Wireless remote controller (WRC) ++CONFIG_SUSPEND_TYPE = 0 ++CONFIG_WOW_STA_MIX = n ++CONFIG_GPIO_WAKEUP = n ++CONFIG_WAKEUP_GPIO_IDX = default ++CONFIG_HIGH_ACTIVE_DEV2HST = n ++######### only for USB ######### ++CONFIG_ONE_PIN_GPIO = n ++CONFIG_HIGH_ACTIVE_HST2DEV = n ++CONFIG_PNO_SUPPORT = n ++CONFIG_PNO_SET_DEBUG = n ++CONFIG_AP_WOWLAN = n ++######### Notify SDIO Host Keep Power During Syspend ########## ++CONFIG_RTW_SDIO_PM_KEEP_POWER = y ++###################### MP HW TX MODE FOR VHT ####################### ++CONFIG_MP_VHT_HW_TX_MODE = n ++###################### Platform Related ####################### ++CONFIG_PLATFORM_I386_PC = y ++CONFIG_PLATFORM_ANDROID_ARM64 = n ++CONFIG_PLATFORM_ARM_RPI = n ++CONFIG_PLATFORM_ARM64_RPI = n ++CONFIG_PLATFORM_ARM_NV_NANO = n ++CONFIG_PLATFORM_ANDROID_X86 = n ++CONFIG_PLATFORM_ANDROID_INTEL_X86 = n ++CONFIG_PLATFORM_JB_X86 = n ++CONFIG_PLATFORM_OPENWRT_NEO2 = n ++CONFIG_PLATFORM_ARM_S3C2K4 = n ++CONFIG_PLATFORM_ARM_PXA2XX = n ++CONFIG_PLATFORM_ARM_S3C6K4 = n ++CONFIG_PLATFORM_MIPS_RMI = n ++CONFIG_PLATFORM_RTD2880B = n ++CONFIG_PLATFORM_MIPS_AR9132 = n ++CONFIG_PLATFORM_RTK_DMP = n ++CONFIG_PLATFORM_MIPS_PLM = n ++CONFIG_PLATFORM_MSTAR389 = n ++CONFIG_PLATFORM_MT53XX = n ++CONFIG_PLATFORM_ARM_MX51_241H = n ++CONFIG_PLATFORM_FS_MX61 = n ++CONFIG_PLATFORM_ACTIONS_ATJ227X = n ++CONFIG_PLATFORM_TEGRA3_CARDHU = n ++CONFIG_PLATFORM_TEGRA4_DALMORE = n ++CONFIG_PLATFORM_ARM_TCC8900 = n ++CONFIG_PLATFORM_ARM_TCC8920 = n ++CONFIG_PLATFORM_ARM_TCC8920_JB42 = n ++CONFIG_PLATFORM_ARM_TCC8930_JB42 = n ++CONFIG_PLATFORM_ARM_RK2818 = n ++CONFIG_PLATFORM_ARM_RK3066 = n ++CONFIG_PLATFORM_ARM_RK3188 = n ++CONFIG_PLATFORM_ARM_URBETTER = n ++CONFIG_PLATFORM_ARM_TI_PANDA = n ++CONFIG_PLATFORM_MIPS_JZ4760 = n ++CONFIG_PLATFORM_DMP_PHILIPS = n ++CONFIG_PLATFORM_MSTAR_TITANIA12 = n ++CONFIG_PLATFORM_MSTAR = n ++CONFIG_PLATFORM_SZEBOOK = n ++CONFIG_PLATFORM_ARM_SUNxI = n ++CONFIG_PLATFORM_ARM_SUN6I = n ++CONFIG_PLATFORM_ARM_SUN7I = n ++CONFIG_PLATFORM_ARM_SUN8I_W3P1 = n ++CONFIG_PLATFORM_ARM_SUN8I_W5P1 = n ++CONFIG_PLATFORM_ACTIONS_ATM702X = n ++CONFIG_PLATFORM_ACTIONS_ATV5201 = n ++CONFIG_PLATFORM_ACTIONS_ATM705X = n ++CONFIG_PLATFORM_ARM_SUN50IW1P1 = n ++CONFIG_PLATFORM_ARM_RTD299X = n ++CONFIG_PLATFORM_ARM_LGE = n ++CONFIG_PLATFORM_ARM_SPREADTRUM_6820 = n ++CONFIG_PLATFORM_ARM_SPREADTRUM_8810 = n ++CONFIG_PLATFORM_ARM_WMT = n ++CONFIG_PLATFORM_TI_DM365 = n ++CONFIG_PLATFORM_MOZART = n ++CONFIG_PLATFORM_RTK119X = n ++CONFIG_PLATFORM_RTK119X_AM = n ++CONFIG_PLATFORM_RTK129X = n ++CONFIG_PLATFORM_RTK390X = n ++CONFIG_PLATFORM_NOVATEK_NT72668 = n ++CONFIG_PLATFORM_HISILICON = n ++CONFIG_PLATFORM_HISILICON_HI3798 = n ++CONFIG_PLATFORM_NV_TK1 = n ++CONFIG_PLATFORM_NV_TK1_UBUNTU = n ++CONFIG_PLATFORM_RTL8197D = n ++CONFIG_PLATFORM_AML_S905 = n ++CONFIG_PLATFORM_ZTE_ZX296716 = n ++CONFIG_PLATFORM_ARM_ODROIDC2 = n ++CONFIG_PLATFORM_PPC = n ++########### CUSTOMER ################################ ++CONFIG_CUSTOMER_HUAWEI_GENERAL = n ++ ++CONFIG_DRVEXT_MODULE = n ++ ++ifeq ($(CONFIG_RTL8812AU), ) ++ifneq (,$(findstring /usr/lib/dkms,$(PATH))) ++ export TopDIR ?= $(shell pwd) ++else ++export TopDIR ?= $(srctree)/$(src) ++endif ++endif ++ ++########### COMMON ################################# ++ifeq ($(CONFIG_USB_HCI), y) ++HCI_NAME = usb ++endif ++ ++ifeq ($(CONFIG_RTL8812A)_$(CONFIG_RTL8821A)_$(CONFIG_RTL8814A), y_y_n) ++ ++EXTRA_CFLAGS += -DDRV_NAME=\"rtl88XXau\" ++ifeq ($(CONFIG_USB_HCI), y) ++USER_MODULE_NAME = 88XXau ++endif ++else ++EXTRA_CFLAGS += -DDRV_NAME=\"rtl8812au\" ++endif ++ ++_OS_INTFS_FILES := os_dep/osdep_service.o \ ++ os_dep/linux/os_intfs.o \ ++ os_dep/linux/$(HCI_NAME)_intf.o \ ++ os_dep/linux/$(HCI_NAME)_ops_linux.o \ ++ os_dep/linux/ioctl_linux.o \ ++ os_dep/linux/xmit_linux.o \ ++ os_dep/linux/mlme_linux.o \ ++ os_dep/linux/recv_linux.o \ ++ os_dep/linux/ioctl_cfg80211.o \ ++ os_dep/linux/wifi_regd.o \ ++ os_dep/linux/rtw_android.o \ ++ os_dep/linux/rtw_proc.o \ ++ os_dep/linux/rtw_rhashtable.o ++ ++ifeq ($(CONFIG_MP_INCLUDED), y) ++_OS_INTFS_FILES += os_dep/linux/ioctl_mp.o ++endif ++ ++_HAL_INTFS_FILES := hal/hal_intf.o \ ++ hal/hal_com.o \ ++ hal/hal_com_phycfg.o \ ++ hal/hal_phy.o \ ++ hal/hal_dm.o \ ++ hal/hal_dm_acs.o \ ++ hal/hal_btcoex_wifionly.o \ ++ hal/hal_btcoex.o \ ++ hal/hal_mp.o \ ++ hal/hal_mcc.o \ ++ hal/hal_hci/hal_$(HCI_NAME).o \ ++ hal/led/hal_led.o \ ++ hal/led/hal_$(HCI_NAME)_led.o ++ ++ ++EXTRA_CFLAGS += -I$(src)/platform ++_PLATFORM_FILES := platform/platform_ops.o ++ ++EXTRA_CFLAGS += -I$(src)/hal/btc ++ ++########### HAL_RTL8188E ################################# ++ifeq ($(CONFIG_RTL8188E), y) ++ ++RTL871X = rtl8188e ++ifeq ($(CONFIG_SDIO_HCI), y) ++MODULE_NAME = 8189es ++endif ++ ++ifeq ($(CONFIG_GSPI_HCI), y) ++MODULE_NAME = 8189es ++endif ++ ++ifeq ($(CONFIG_USB_HCI), y) ++MODULE_NAME = 8188eu ++endif ++ ++ifeq ($(CONFIG_PCI_HCI), y) ++MODULE_NAME = 8188ee ++endif ++EXTRA_CFLAGS += -DCONFIG_RTL8188E ++ ++_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ ++ hal/$(RTL871X)/Hal8188EPwrSeq.o\ ++ hal/$(RTL871X)/$(RTL871X)_xmit.o\ ++ hal/$(RTL871X)/$(RTL871X)_sreset.o ++ ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ ++ hal/$(RTL871X)/$(RTL871X)_phycfg.o \ ++ hal/$(RTL871X)/$(RTL871X)_rf6052.o \ ++ hal/$(RTL871X)/$(RTL871X)_dm.o \ ++ hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ ++ hal/$(RTL871X)/$(RTL871X)_cmd.o \ ++ hal/$(RTL871X)/hal8188e_s_fw.o \ ++ hal/$(RTL871X)/hal8188e_t_fw.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o ++ ++ifeq ($(CONFIG_SDIO_HCI), y) ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o ++else ++ifeq ($(CONFIG_GSPI_HCI), y) ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o ++else ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o ++endif ++endif ++ ++ifeq ($(CONFIG_USB_HCI), y) ++_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188E_USB.o ++endif ++ifeq ($(CONFIG_PCI_HCI), y) ++_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188E_PCIE.o ++endif ++ifeq ($(CONFIG_SDIO_HCI), y) ++_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188E_SDIO.o ++endif ++endif ++ ++########### HAL_RTL8812A_RTL8821A ################################# ++ ++ifneq ($(CONFIG_RTL8812A)_$(CONFIG_RTL8821A), n_n) ++ ++RTL871X = rtl8812a ++ifeq ($(CONFIG_USB_HCI), y) ++MODULE_NAME = 8812au ++endif ++ifeq ($(CONFIG_PCI_HCI), y) ++MODULE_NAME = 8812ae ++endif ++ifeq ($(CONFIG_SDIO_HCI), y) ++MODULE_NAME = 8812as ++endif ++ ++_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ ++ hal/$(RTL871X)/Hal8812PwrSeq.o \ ++ hal/$(RTL871X)/Hal8821APwrSeq.o\ ++ hal/$(RTL871X)/$(RTL871X)_xmit.o\ ++ hal/$(RTL871X)/$(RTL871X)_sreset.o ++ ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ ++ hal/$(RTL871X)/$(RTL871X)_phycfg.o \ ++ hal/$(RTL871X)/$(RTL871X)_rf6052.o \ ++ hal/$(RTL871X)/$(RTL871X)_dm.o \ ++ hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ ++ hal/$(RTL871X)/$(RTL871X)_cmd.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o ++ ++ifeq ($(CONFIG_SDIO_HCI), y) ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o ++else ++ifeq ($(CONFIG_GSPI_HCI), y) ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o ++else ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o ++endif ++endif ++ ++ifeq ($(CONFIG_RTL8812A), y) ++ifeq ($(CONFIG_USB_HCI), y) ++_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8812A_USB.o ++endif ++ifeq ($(CONFIG_PCI_HCI), y) ++_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8812A_PCIE.o ++endif ++endif ++ifeq ($(CONFIG_RTL8821A), y) ++ifeq ($(CONFIG_USB_HCI), y) ++_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8821A_USB.o ++endif ++ifeq ($(CONFIG_PCI_HCI), y) ++_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8821A_PCIE.o ++endif ++ifeq ($(CONFIG_SDIO_HCI), y) ++_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8821A_SDIO.o ++endif ++endif ++ ++ifeq ($(CONFIG_RTL8812A), y) ++EXTRA_CFLAGS += -DCONFIG_RTL8812A ++_HAL_INTFS_FILES += hal/rtl8812a/hal8812a_fw.o ++endif ++ ++ifeq ($(CONFIG_RTL8821A), y) ++ ++ifeq ($(CONFIG_RTL8812A), n) ++ ++RTL871X = rtl8821a ++ifeq ($(CONFIG_USB_HCI), y) ++ifeq ($(CONFIG_BT_COEXIST), y) ++MODULE_NAME := 8821au ++else ++MODULE_NAME := 8811au ++endif ++endif ++ifeq ($(CONFIG_PCI_HCI), y) ++MODULE_NAME := 8821ae ++endif ++ifeq ($(CONFIG_SDIO_HCI), y) ++MODULE_NAME := 8821as ++endif ++ ++endif ++ ++EXTRA_CFLAGS += -DCONFIG_RTL8821A ++ ++_HAL_INTFS_FILES += hal/rtl8812a/hal8821a_fw.o ++ ++endif ++ ++ifeq ($(CONFIG_BT_COEXIST), y) ++ifeq ($(CONFIG_RTL8812A), y) ++_BTC_FILES += hal/btc/halbtc8812a1ant.o \ ++ hal/btc/halbtc8812a2ant.o ++endif ++ifeq ($(CONFIG_RTL8821A), y) ++_BTC_FILES += hal/btc/halbtc8821a1ant.o \ ++ hal/btc/halbtc8821a2ant.o ++endif ++endif ++ ++endif ++ ++########### HAL_RTL8723B ################################# ++ifeq ($(CONFIG_RTL8723B), y) ++ ++RTL871X = rtl8723b ++ifeq ($(CONFIG_USB_HCI), y) ++MODULE_NAME = 8723bu ++endif ++ifeq ($(CONFIG_PCI_HCI), y) ++MODULE_NAME = 8723be ++endif ++ifeq ($(CONFIG_SDIO_HCI), y) ++MODULE_NAME = 8723bs ++endif ++ ++EXTRA_CFLAGS += -DCONFIG_RTL8723B ++ ++_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ ++ hal/$(RTL871X)/Hal8723BPwrSeq.o\ ++ hal/$(RTL871X)/$(RTL871X)_sreset.o ++ ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ ++ hal/$(RTL871X)/$(RTL871X)_phycfg.o \ ++ hal/$(RTL871X)/$(RTL871X)_rf6052.o \ ++ hal/$(RTL871X)/$(RTL871X)_dm.o \ ++ hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ ++ hal/$(RTL871X)/$(RTL871X)_cmd.o \ ++ hal/$(RTL871X)/hal8723b_fw.o ++ ++_HAL_INTFS_FILES += \ ++ hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o ++ ++ifeq ($(CONFIG_PCI_HCI), y) ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o ++else ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o ++endif ++ ++ifeq ($(CONFIG_USB_HCI), y) ++_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8723B_USB.o ++endif ++ifeq ($(CONFIG_PCI_HCI), y) ++_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8723B_PCIE.o ++endif ++ifeq ($(CONFIG_SDIO_HCI), y) ++_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8723B_SDIO.o ++endif ++ ++_BTC_FILES += hal/btc/halbtc8723bwifionly.o ++ifeq ($(CONFIG_BT_COEXIST), y) ++_BTC_FILES += hal/btc/halbtc8723b1ant.o \ ++ hal/btc/halbtc8723b2ant.o ++endif ++ ++endif ++ ++########### HAL_RTL8814A ################################# ++ifeq ($(CONFIG_RTL8814A), y) ++## ADD NEW VHT MP HW TX MODE ## ++#EXTRA_CFLAGS += -DCONFIG_MP_VHT_HW_TX_MODE ++CONFIG_MP_VHT_HW_TX_MODE = n ++########################################## ++#RTL871X = rtl8814a ++ifeq ($(CONFIG_USB_HCI), y) ++MODULE_NAME = 8814au ++endif ++ ++EXTRA_CFLAGS += -DCONFIG_RTL8814A ++ ++_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ ++ hal/$(RTL871X)/Hal8814PwrSeq.o \ ++ hal/$(RTL871X)/$(RTL871X)_xmit.o\ ++ hal/$(RTL871X)/$(RTL871X)_sreset.o ++ ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ ++ hal/$(RTL871X)/$(RTL871X)_phycfg.o \ ++ hal/$(RTL871X)/$(RTL871X)_rf6052.o \ ++ hal/$(RTL871X)/$(RTL871X)_dm.o \ ++ hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ ++ hal/$(RTL871X)/$(RTL871X)_cmd.o \ ++ hal/$(RTL871X)/hal8814a_fw.o ++ ++ ++_HAL_INTFS_FILES += \ ++ hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o ++ ++ifeq ($(CONFIG_SDIO_HCI), y) ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o ++else ++ifeq ($(CONFIG_GSPI_HCI), y) ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o ++else ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o ++endif ++endif ++ ++ifeq ($(CONFIG_USB_HCI), y) ++_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8814A_USB.o ++endif ++ifeq ($(CONFIG_PCI_HCI), y) ++_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8814A_PCIE.o ++endif ++ ++endif ++ ++########### HAL_RTL8723C ################################# ++ifeq ($(CONFIG_RTL8723C), y) ++ ++RTL871X = rtl8703b ++ifeq ($(CONFIG_USB_HCI), y) ++MODULE_NAME = 8723cu ++MODULE_SUB_NAME = 8703bu ++endif ++ifeq ($(CONFIG_PCI_HCI), y) ++MODULE_NAME = 8723ce ++MODULE_SUB_NAME = 8703be ++endif ++ifeq ($(CONFIG_SDIO_HCI), y) ++MODULE_NAME = 8723cs ++MODULE_SUB_NAME = 8703bs ++endif ++ ++EXTRA_CFLAGS += -DCONFIG_RTL8703B ++ ++_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ ++ hal/$(RTL871X)/Hal8703BPwrSeq.o\ ++ hal/$(RTL871X)/$(RTL871X)_sreset.o ++ ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ ++ hal/$(RTL871X)/$(RTL871X)_phycfg.o \ ++ hal/$(RTL871X)/$(RTL871X)_rf6052.o \ ++ hal/$(RTL871X)/$(RTL871X)_dm.o \ ++ hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ ++ hal/$(RTL871X)/$(RTL871X)_cmd.o \ ++ hal/$(RTL871X)/hal8703b_fw.o ++ ++_HAL_INTFS_FILES += \ ++ hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_led.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_xmit.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_recv.o ++ ++ifeq ($(CONFIG_PCI_HCI), y) ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o ++else ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o ++endif ++ ++ifeq ($(CONFIG_USB_HCI), y) ++_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8703B_USB.o ++endif ++ifeq ($(CONFIG_PCI_HCI), y) ++_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8703B_PCIE.o ++endif ++ ++ifeq ($(CONFIG_BT_COEXIST), y) ++_BTC_FILES += hal/btc/halbtc8703b1ant.o ++endif ++ ++endif ++ ++########### HAL_RTL8723D ################################# ++ifeq ($(CONFIG_RTL8723D), y) ++ ++RTL871X = rtl8723d ++ifeq ($(CONFIG_USB_HCI), y) ++MODULE_NAME = 8723du ++MODULE_SUB_NAME = 8723du ++endif ++ifeq ($(CONFIG_PCI_HCI), y) ++MODULE_NAME = 8723de ++MODULE_SUB_NAME = 8723de ++endif ++ifeq ($(CONFIG_SDIO_HCI), y) ++MODULE_NAME = 8723ds ++MODULE_SUB_NAME = 8723ds ++endif ++ ++EXTRA_CFLAGS += -DCONFIG_RTL8723D ++ ++_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ ++ hal/$(RTL871X)/Hal8723DPwrSeq.o\ ++ hal/$(RTL871X)/$(RTL871X)_sreset.o ++ ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ ++ hal/$(RTL871X)/$(RTL871X)_phycfg.o \ ++ hal/$(RTL871X)/$(RTL871X)_rf6052.o \ ++ hal/$(RTL871X)/$(RTL871X)_dm.o \ ++ hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ ++ hal/$(RTL871X)/$(RTL871X)_cmd.o \ ++ hal/$(RTL871X)/hal8723d_fw.o \ ++ hal/$(RTL871X)/$(RTL871X)_lps_poff.o ++ ++ ++_HAL_INTFS_FILES += \ ++ hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_led.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_xmit.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_recv.o ++ ++ifeq ($(CONFIG_PCI_HCI), y) ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o ++else ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o ++endif ++ ++ifeq ($(CONFIG_USB_HCI), y) ++_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8723D_USB.o ++endif ++ifeq ($(CONFIG_PCI_HCI), y) ++_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8723D_PCIE.o ++endif ++ ++ifeq ($(CONFIG_BT_COEXIST), y) ++_BTC_FILES += hal/btc/halbtc8723d1ant.o \ ++ hal/btc/halbtc8723d2ant.o ++endif ++ ++endif ++ ++########### HAL_RTL8188F ################################# ++ifeq ($(CONFIG_RTL8188F), y) ++ ++RTL871X = rtl8188f ++ifeq ($(CONFIG_USB_HCI), y) ++MODULE_NAME = 8188fu ++endif ++ifeq ($(CONFIG_PCI_HCI), y) ++MODULE_NAME = 8188fe ++endif ++ifeq ($(CONFIG_SDIO_HCI), y) ++MODULE_NAME = 8189fs ++endif ++ ++EXTRA_CFLAGS += -DCONFIG_RTL8188F ++ ++_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ ++ hal/$(RTL871X)/Hal8188FPwrSeq.o\ ++ hal/$(RTL871X)/$(RTL871X)_sreset.o ++ ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ ++ hal/$(RTL871X)/$(RTL871X)_phycfg.o \ ++ hal/$(RTL871X)/$(RTL871X)_rf6052.o \ ++ hal/$(RTL871X)/$(RTL871X)_dm.o \ ++ hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ ++ hal/$(RTL871X)/$(RTL871X)_cmd.o \ ++ hal/$(RTL871X)/hal8188f_fw.o ++ ++_HAL_INTFS_FILES += \ ++ hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o ++ ++ifeq ($(CONFIG_PCI_HCI), y) ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o ++else ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o ++endif ++ ++ifeq ($(CONFIG_USB_HCI), y) ++_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188F_USB.o ++endif ++ ++ifeq ($(CONFIG_SDIO_HCI), y) ++_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188F_SDIO.o ++endif ++ ++endif ++ ++########### HAL_RTL8188GTV ################################# ++ifeq ($(CONFIG_RTL8188GTV), y) ++ ++RTL871X = rtl8188gtv ++ifeq ($(CONFIG_USB_HCI), y) ++MODULE_NAME = 8188gtvu ++endif ++ifeq ($(CONFIG_SDIO_HCI), y) ++MODULE_NAME = 8189gtvs ++endif ++ ++EXTRA_CFLAGS += -DCONFIG_RTL8188GTV ++ ++_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ ++ hal/$(RTL871X)/Hal8188GTVPwrSeq.o\ ++ hal/$(RTL871X)/$(RTL871X)_sreset.o ++ ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ ++ hal/$(RTL871X)/$(RTL871X)_phycfg.o \ ++ hal/$(RTL871X)/$(RTL871X)_rf6052.o \ ++ hal/$(RTL871X)/$(RTL871X)_dm.o \ ++ hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ ++ hal/$(RTL871X)/$(RTL871X)_cmd.o \ ++ hal/$(RTL871X)/hal8188gtv_fw.o ++ ++_HAL_INTFS_FILES += \ ++ hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o ++ ++ifeq ($(CONFIG_PCI_HCI), y) ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o ++else ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o ++endif ++ ++ifeq ($(CONFIG_USB_HCI), y) ++_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188GTV_USB.o ++endif ++ ++ifeq ($(CONFIG_SDIO_HCI), y) ++_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188GTV_SDIO.o ++endif ++ ++endif ++ ++########### HAL_RTL8822B ################################# ++ifeq ($(CONFIG_RTL8822B), y) ++RTL871X := rtl8822b ++ifeq ($(CONFIG_USB_HCI), y) ++ifeq ($(CONFIG_BT_COEXIST), n) ++MODULE_NAME = 8812bu ++else ++MODULE_NAME = 88x2bu ++endif ++endif ++ifeq ($(CONFIG_PCI_HCI), y) ++MODULE_NAME = 88x2be ++endif ++ifeq ($(CONFIG_SDIO_HCI), y) ++MODULE_NAME = 88x2bs ++endif ++ ++endif ++########### HAL_RTL8821C ################################# ++ifeq ($(CONFIG_RTL8821C), y) ++RTL871X := rtl8821c ++ifeq ($(CONFIG_USB_HCI), y) ++MODULE_NAME = 8821cu ++endif ++ifeq ($(CONFIG_PCI_HCI), y) ++MODULE_NAME = 8821ce ++endif ++ifeq ($(CONFIG_SDIO_HCI), y) ++MODULE_NAME = 8821cs ++endif ++ ++endif ++ ++########### HAL_RTL8710B ################################# ++ifeq ($(CONFIG_RTL8710B), y) ++ ++RTL871X = rtl8710b ++ifeq ($(CONFIG_USB_HCI), y) ++MODULE_NAME = 8710bu ++MODULE_SUB_NAME = 8710bu ++endif ++ ++EXTRA_CFLAGS += -DCONFIG_RTL8710B ++ ++_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ ++ hal/$(RTL871X)/Hal8710BPwrSeq.o\ ++ hal/$(RTL871X)/$(RTL871X)_sreset.o ++ ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ ++ hal/$(RTL871X)/$(RTL871X)_phycfg.o \ ++ hal/$(RTL871X)/$(RTL871X)_rf6052.o \ ++ hal/$(RTL871X)/$(RTL871X)_dm.o \ ++ hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ ++ hal/$(RTL871X)/$(RTL871X)_cmd.o \ ++ hal/$(RTL871X)/hal8710b_fw.o \ ++ hal/$(RTL871X)/$(RTL871X)_lps_poff.o ++ ++ ++_HAL_INTFS_FILES += \ ++ hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_led.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_xmit.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_recv.o ++ ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o ++ ++ifeq ($(CONFIG_USB_HCI), y) ++_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8710B_USB.o ++endif ++ ++endif ++ ++########### HAL_RTL8192F ################################# ++ifeq ($(CONFIG_RTL8192F), y) ++ ++RTL871X = rtl8192f ++ifeq ($(CONFIG_USB_HCI), y) ++MODULE_NAME = 8192fu ++MODULE_SUB_NAME = 8192fu ++endif ++ifeq ($(CONFIG_PCI_HCI), y) ++MODULE_NAME = 8192fe ++MODULE_SUB_NAME = 8192fe ++endif ++ifeq ($(CONFIG_SDIO_HCI), y) ++MODULE_NAME = 8192fs ++MODULE_SUB_NAME = 8192fs ++endif ++ ++EXTRA_CFLAGS += -DCONFIG_RTL8192F ++ ++_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ ++ hal/$(RTL871X)/Hal8192FPwrSeq.o\ ++ hal/$(RTL871X)/$(RTL871X)_sreset.o ++ ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ ++ hal/$(RTL871X)/$(RTL871X)_phycfg.o \ ++ hal/$(RTL871X)/$(RTL871X)_rf6052.o \ ++ hal/$(RTL871X)/$(RTL871X)_dm.o \ ++ hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ ++ hal/$(RTL871X)/$(RTL871X)_cmd.o \ ++ hal/$(RTL871X)/hal8192f_fw.o \ ++ hal/$(RTL871X)/$(RTL871X)_lps_poff.o ++ ++ ++_HAL_INTFS_FILES += \ ++ hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_led.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_xmit.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_recv.o ++ ++ifeq ($(CONFIG_PCI_HCI), y) ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o ++else ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o ++endif ++ ++ifeq ($(CONFIG_SDIO_HCI), y) ++_HAL_INTFS_FILES += hal/efuse/$(RTL871X)/HalEfuseMask8192F_SDIO.o ++endif ++ ++ifeq ($(CONFIG_USB_HCI), y) ++_HAL_INTFS_FILES += hal/efuse/$(RTL871X)/HalEfuseMask8192F_USB.o ++endif ++ ++ifeq ($(CONFIG_PCI_HCI), y) ++_HAL_INTFS_FILES += hal/efuse/$(RTL871X)/HalEfuseMask8192F_PCIE.o ++endif ++ ++endif ++########### AUTO_CFG ################################# ++ ++ifeq ($(CONFIG_AUTOCFG_CP), y) ++ ++ifeq ($(CONFIG_MULTIDRV), y) ++$(shell cp $(TopDIR)/autoconf_multidrv_$(HCI_NAME)_linux.h $(TopDIR)/include/autoconf.h) ++else ++ifeq ($(CONFIG_RTL8188E)$(CONFIG_SDIO_HCI),yy) ++$(shell cp $(TopDIR)/autoconf_rtl8189e_$(HCI_NAME)_linux.h $(TopDIR)/include/autoconf.h) ++else ifeq ($(CONFIG_RTL8188F)$(CONFIG_SDIO_HCI),yy) ++$(shell cp $(TopDIR)/autoconf_rtl8189f_$(HCI_NAME)_linux.h $(TopDIR)/include/autoconf.h) ++else ifeq ($(CONFIG_RTL8723C),y) ++$(shell cp $(TopDIR)/autoconf_rtl8723c_$(HCI_NAME)_linux.h $(TopDIR)/include/autoconf.h) ++else ++$(shell cp $(TopDIR)/autoconf_$(RTL871X)_$(HCI_NAME)_linux.h $(TopDIR)/include/autoconf.h) ++endif ++endif ++ ++endif ++ ++########### END OF PATH ################################# ++ ++ifeq ($(CONFIG_USB_HCI), y) ++ifeq ($(CONFIG_USB_AUTOSUSPEND), y) ++EXTRA_CFLAGS += -DCONFIG_USB_AUTOSUSPEND ++endif ++endif ++ ++ifeq ($(CONFIG_MP_INCLUDED), y) ++#MODULE_NAME := $(MODULE_NAME)_mp ++EXTRA_CFLAGS += -DCONFIG_MP_INCLUDED ++endif ++ ++ifeq ($(CONFIG_POWER_SAVING), y) ++EXTRA_CFLAGS += -DCONFIG_POWER_SAVING ++endif ++ ++ifeq ($(CONFIG_HW_PWRP_DETECTION), y) ++EXTRA_CFLAGS += -DCONFIG_HW_PWRP_DETECTION ++endif ++ ++ifeq ($(CONFIG_BT_COEXIST), y) ++EXTRA_CFLAGS += -DCONFIG_BT_COEXIST ++endif ++ ++ifeq ($(CONFIG_INTEL_WIDI), y) ++EXTRA_CFLAGS += -DCONFIG_INTEL_WIDI ++endif ++ ++ifeq ($(CONFIG_WAPI_SUPPORT), y) ++EXTRA_CFLAGS += -DCONFIG_WAPI_SUPPORT ++endif ++ ++ ++ifeq ($(CONFIG_EFUSE_CONFIG_FILE), y) ++EXTRA_CFLAGS += -DCONFIG_EFUSE_CONFIG_FILE ++ ++#EFUSE_MAP_PATH ++USER_EFUSE_MAP_PATH ?= ++ifneq ($(USER_EFUSE_MAP_PATH),) ++EXTRA_CFLAGS += -DEFUSE_MAP_PATH=\"$(USER_EFUSE_MAP_PATH)\" ++else ifeq ($(MODULE_NAME), 8189es) ++EXTRA_CFLAGS += -DEFUSE_MAP_PATH=\"/system/etc/wifi/wifi_efuse_8189e.map\" ++else ifeq ($(MODULE_NAME), 8723bs) ++EXTRA_CFLAGS += -DEFUSE_MAP_PATH=\"/system/etc/wifi/wifi_efuse_8723bs.map\" ++else ++EXTRA_CFLAGS += -DEFUSE_MAP_PATH=\"/system/etc/wifi/wifi_efuse_$(MODULE_NAME).map\" ++endif ++ ++#WIFIMAC_PATH ++USER_WIFIMAC_PATH ?= ++ifneq ($(USER_WIFIMAC_PATH),) ++EXTRA_CFLAGS += -DWIFIMAC_PATH=\"$(USER_WIFIMAC_PATH)\" ++else ++EXTRA_CFLAGS += -DWIFIMAC_PATH=\"/data/wifimac.txt\" ++endif ++ ++endif ++ ++ifeq ($(CONFIG_EXT_CLK), y) ++EXTRA_CFLAGS += -DCONFIG_EXT_CLK ++endif ++ ++ifeq ($(CONFIG_TRAFFIC_PROTECT), y) ++EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT ++endif ++ ++ifeq ($(CONFIG_LOAD_PHY_PARA_FROM_FILE), y) ++EXTRA_CFLAGS += -DCONFIG_LOAD_PHY_PARA_FROM_FILE ++#EXTRA_CFLAGS += -DREALTEK_CONFIG_PATH_WITH_IC_NAME_FOLDER ++EXTRA_CFLAGS += -DREALTEK_CONFIG_PATH=\"/lib/firmware/\" ++endif ++ ++ifeq ($(CONFIG_TXPWR_BY_RATE), n) ++EXTRA_CFLAGS += -DCONFIG_TXPWR_BY_RATE=0 ++else ifeq ($(CONFIG_TXPWR_BY_RATE), y) ++EXTRA_CFLAGS += -DCONFIG_TXPWR_BY_RATE=1 ++endif ++ifeq ($(CONFIG_TXPWR_BY_RATE_EN), n) ++EXTRA_CFLAGS += -DCONFIG_TXPWR_BY_RATE_EN=0 ++else ifeq ($(CONFIG_TXPWR_BY_RATE_EN), y) ++EXTRA_CFLAGS += -DCONFIG_TXPWR_BY_RATE_EN=1 ++else ifeq ($(CONFIG_TXPWR_BY_RATE_EN), auto) ++EXTRA_CFLAGS += -DCONFIG_TXPWR_BY_RATE_EN=2 ++endif ++ ++ifeq ($(CONFIG_TXPWR_LIMIT), n) ++EXTRA_CFLAGS += -DCONFIG_TXPWR_LIMIT=0 ++else ifeq ($(CONFIG_TXPWR_LIMIT), y) ++EXTRA_CFLAGS += -DCONFIG_TXPWR_LIMIT=1 ++endif ++ifeq ($(CONFIG_TXPWR_LIMIT_EN), n) ++EXTRA_CFLAGS += -DCONFIG_TXPWR_LIMIT_EN=0 ++else ifeq ($(CONFIG_TXPWR_LIMIT_EN), y) ++EXTRA_CFLAGS += -DCONFIG_TXPWR_LIMIT_EN=1 ++else ifeq ($(CONFIG_TXPWR_LIMIT_EN), auto) ++EXTRA_CFLAGS += -DCONFIG_TXPWR_LIMIT_EN=2 ++endif ++ ++ifneq ($(CONFIG_RTW_CHPLAN), 0xFF) ++EXTRA_CFLAGS += -DCONFIG_RTW_CHPLAN=$(CONFIG_RTW_CHPLAN) ++endif ++ ++ifeq ($(CONFIG_CALIBRATE_TX_POWER_BY_REGULATORY), y) ++EXTRA_CFLAGS += -DCONFIG_CALIBRATE_TX_POWER_BY_REGULATORY ++endif ++ ++ifeq ($(CONFIG_CALIBRATE_TX_POWER_TO_MAX), y) ++EXTRA_CFLAGS += -DCONFIG_CALIBRATE_TX_POWER_TO_MAX ++endif ++ ++ifeq ($(CONFIG_RTW_ADAPTIVITY_EN), disable) ++EXTRA_CFLAGS += -DCONFIG_RTW_ADAPTIVITY_EN=0 ++else ifeq ($(CONFIG_RTW_ADAPTIVITY_EN), enable) ++EXTRA_CFLAGS += -DCONFIG_RTW_ADAPTIVITY_EN=1 ++endif ++ ++ifeq ($(CONFIG_RTW_ADAPTIVITY_MODE), normal) ++EXTRA_CFLAGS += -DCONFIG_RTW_ADAPTIVITY_MODE=0 ++else ifeq ($(CONFIG_RTW_ADAPTIVITY_MODE), carrier_sense) ++EXTRA_CFLAGS += -DCONFIG_RTW_ADAPTIVITY_MODE=1 ++endif ++ ++ifeq ($(CONFIG_SIGNAL_SCALE_MAPPING), y) ++EXTRA_CFLAGS += -DCONFIG_SIGNAL_SCALE_MAPPING ++endif ++ ++ifeq ($(CONFIG_80211W), y) ++EXTRA_CFLAGS += -DCONFIG_IEEE80211W ++endif ++ ++ifeq ($(CONFIG_WOWLAN), y) ++EXTRA_CFLAGS += -DCONFIG_WOWLAN -DRTW_WAKEUP_EVENT=$(CONFIG_WAKEUP_TYPE) ++EXTRA_CFLAGS += -DRTW_SUSPEND_TYPE=$(CONFIG_SUSPEND_TYPE) ++ifeq ($(CONFIG_WOW_STA_MIX), y) ++EXTRA_CFLAGS += -DRTW_WOW_STA_MIX ++endif ++ifeq ($(CONFIG_SDIO_HCI), y) ++EXTRA_CFLAGS += -DCONFIG_RTW_SDIO_PM_KEEP_POWER ++endif ++endif ++ ++ifeq ($(CONFIG_AP_WOWLAN), y) ++EXTRA_CFLAGS += -DCONFIG_AP_WOWLAN ++ifeq ($(CONFIG_SDIO_HCI), y) ++EXTRA_CFLAGS += -DCONFIG_RTW_SDIO_PM_KEEP_POWER ++endif ++endif ++ ++ifeq ($(CONFIG_PNO_SUPPORT), y) ++EXTRA_CFLAGS += -DCONFIG_PNO_SUPPORT ++ifeq ($(CONFIG_PNO_SET_DEBUG), y) ++EXTRA_CFLAGS += -DCONFIG_PNO_SET_DEBUG ++endif ++endif ++ ++ifeq ($(CONFIG_GPIO_WAKEUP), y) ++EXTRA_CFLAGS += -DCONFIG_GPIO_WAKEUP ++ifeq ($(CONFIG_ONE_PIN_GPIO), y) ++EXTRA_CFLAGS += -DCONFIG_RTW_ONE_PIN_GPIO ++endif ++ifeq ($(CONFIG_HIGH_ACTIVE_DEV2HST), y) ++EXTRA_CFLAGS += -DHIGH_ACTIVE_DEV2HST=1 ++else ++EXTRA_CFLAGS += -DHIGH_ACTIVE_DEV2HST=0 ++endif ++endif ++ ++ifeq ($(CONFIG_HIGH_ACTIVE_HST2DEV), y) ++EXTRA_CFLAGS += -DHIGH_ACTIVE_HST2DEV=1 ++else ++EXTRA_CFLAGS += -DHIGH_ACTIVE_HST2DEV=0 ++endif ++ ++ifneq ($(CONFIG_WAKEUP_GPIO_IDX), default) ++EXTRA_CFLAGS += -DWAKEUP_GPIO_IDX=$(CONFIG_WAKEUP_GPIO_IDX) ++endif ++ ++ifeq ($(CONFIG_RTW_SDIO_PM_KEEP_POWER), y) ++ifeq ($(CONFIG_SDIO_HCI), y) ++EXTRA_CFLAGS += -DCONFIG_RTW_SDIO_PM_KEEP_POWER ++endif ++endif ++ ++ifeq ($(CONFIG_REDUCE_TX_CPU_LOADING), y) ++EXTRA_CFLAGS += -DCONFIG_REDUCE_TX_CPU_LOADING ++endif ++ ++ifeq ($(CONFIG_BR_EXT), y) ++BR_NAME = br0 ++EXTRA_CFLAGS += -DCONFIG_BR_EXT ++EXTRA_CFLAGS += '-DCONFIG_BR_EXT_BRNAME="'$(BR_NAME)'"' ++endif ++ ++ ++ifeq ($(CONFIG_TDLS), y) ++EXTRA_CFLAGS += -DCONFIG_TDLS ++endif ++ ++ifeq ($(CONFIG_WIFI_MONITOR), y) ++EXTRA_CFLAGS += -DCONFIG_WIFI_MONITOR ++endif ++ ++ifeq ($(CONFIG_MCC_MODE), y) ++EXTRA_CFLAGS += -DCONFIG_MCC_MODE ++endif ++ ++ifeq ($(CONFIG_RTW_NAPI), y) ++EXTRA_CFLAGS += -DCONFIG_RTW_NAPI ++endif ++ ++ifeq ($(CONFIG_RTW_GRO), y) ++EXTRA_CFLAGS += -DCONFIG_RTW_GRO ++endif ++ ++ifeq ($(CONFIG_RTW_REPEATER_SON), y) ++EXTRA_CFLAGS += -DCONFIG_RTW_REPEATER_SON ++endif ++ ++ifeq ($(CONFIG_RTW_IPCAM_APPLICATION), y) ++EXTRA_CFLAGS += -DCONFIG_RTW_IPCAM_APPLICATION ++ifeq ($(CONFIG_WIFI_MONITOR), n) ++EXTRA_CFLAGS += -DCONFIG_WIFI_MONITOR ++endif ++endif ++ ++ifeq ($(CONFIG_RTW_NETIF_SG), y) ++EXTRA_CFLAGS += -DCONFIG_RTW_NETIF_SG ++endif ++ ++ifeq ($(CONFIG_TX_CSUM_OFFLOAD), y) ++EXTRA_CFLAGS += -DCONFIG_TX_CSUM_OFFLOAD ++endif ++ ++ifeq ($(CONFIG_ICMP_VOQ), y) ++EXTRA_CFLAGS += -DCONFIG_ICMP_VOQ ++endif ++ ++ifeq ($(CONFIG_IP_R_MONITOR), y) ++EXTRA_CFLAGS += -DCONFIG_IP_R_MONITOR ++endif ++ ++ifeq ($(CONFIG_RTW_WIFI_HAL), y) ++#EXTRA_CFLAGS += -DCONFIG_RTW_WIFI_HAL_DEBUG ++EXTRA_CFLAGS += -DCONFIG_RTW_WIFI_HAL ++EXTRA_CFLAGS += -DCONFIG_RTW_CFGVEDNOR_LLSTATS ++EXTRA_CFLAGS += -DCONFIG_RTW_CFGVENDOR_RANDOM_MAC_OUI ++EXTRA_CFLAGS += -DCONFIG_RTW_CFGVEDNOR_RSSIMONITOR ++EXTRA_CFLAGS += -DCONFIG_RTW_CFGVENDOR_WIFI_LOGGER ++endif ++ ++ifeq ($(CONFIG_MP_VHT_HW_TX_MODE), y) ++EXTRA_CFLAGS += -DCONFIG_MP_VHT_HW_TX_MODE ++endif ++ ++ifeq ($(CONFIG_APPEND_VENDOR_IE_ENABLE), y) ++EXTRA_CFLAGS += -DCONFIG_APPEND_VENDOR_IE_ENABLE ++endif ++ ++ifeq ($(CONFIG_RTW_DEBUG), y) ++EXTRA_CFLAGS += -DCONFIG_RTW_DEBUG ++EXTRA_CFLAGS += -DRTW_LOG_LEVEL=$(CONFIG_RTW_LOG_LEVEL) ++endif ++ ++EXTRA_CFLAGS += -DDM_ODM_SUPPORT_TYPE=0x04 ++ ++ifeq ($(CONFIG_PLATFORM_I386_PC), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++SUBARCH := $(shell uname -m | sed -e "s/i.86/i386/; s/ppc/powerpc/; s/armv.l/arm/; s/aarch64/arm64/;") ++ARCH ?= $(SUBARCH) ++CROSS_COMPILE ?= ++KVER := $(shell uname -r) ++KSRC := /lib/modules/$(KVER)/build ++MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/ ++INSTALL_PREFIX := ++STAGINGMODDIR := /lib/modules/$(KVER)/kernel/drivers/staging ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_RPI), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++ARCH ?= arm ++CROSS_COMPILE ?= ++KVER ?= $(shell uname -r) ++KSRC := /lib/modules/$(KVER)/build ++MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/ ++INSTALL_PREFIX := ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM64_RPI), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++ARCH ?= arm64 ++CROSS_COMPILE ?= ++KVER ?= $(shell uname -r) ++KSRC := /lib/modules/$(KVER)/build ++MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/ ++INSTALL_PREFIX := ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_NV_NANO), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++ARCH := arm64 ++KVER := $(shell uname -r) ++KSRC := /lib/modules/$(KVER)/build ++MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/ ++INSTALL_PREFIX := ++STAGINGMODDIR := /lib/modules/$(KVER)/kernel/drivers/staging ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_ODROIDC2), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++ARCH ?= arm64 ++CROSS_COMPILE ?= ++KVER ?= $(shell uname -r) ++KSRC := /lib/modules/$(KVER)/build ++MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/ ++INSTALL_PREFIX := ++endif ++ ++ifeq ($(CONFIG_PLATFORM_PPC), y) ++EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN ++SUBARCH := $(shell uname -m | sed -e s/ppc/powerpc/) ++ARCH ?= $(SUBARCH) ++CROSS_COMPILE ?= ++KVER ?= $(shell uname -r) ++KSRC := /lib/modules/$(KVER)/build ++MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/ ++INSTALL_PREFIX := ++endif ++ ++ifeq ($(CONFIG_PLATFORM_NV_TK1), y) ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_NV_TK1 ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++# default setting for Android 4.1, 4.2 ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_P2P_IPS -DCONFIG_PLATFORM_ANDROID ++# Enable this for Android 5.0 ++EXTRA_CFLAGS += -DCONFIG_RADIO_WORK ++EXTRA_CFLAGS += -DRTW_VENDOR_EXT_SUPPORT ++EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC ++ARCH ?= arm ++ ++CROSS_COMPILE := /mnt/newdisk/android_sdk/nvidia_tk1/android_L/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi- ++KSRC :=/mnt/newdisk/android_sdk/nvidia_tk1/android_L/out/target/product/shieldtablet/obj/KERNEL/ ++MODULE_NAME = wlan ++endif ++ ++ifeq ($(CONFIG_PLATFORM_NV_TK1_UBUNTU), y) ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_NV_TK1 ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++ ++ARCH ?= arm ++ ++CROSS_COMPILE ?= ++KVER := $(shell uname -r) ++KSRC := /lib/modules/$(KVER)/build ++MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/ ++INSTALL_PREFIX := ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ACTIONS_ATM702X), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -DCONFIG_PLATFORM_ACTIONS_ATM702X ++#ARCH := arm ++ARCH := $(R_ARCH) ++#CROSS_COMPILE := arm-none-linux-gnueabi- ++CROSS_COMPILE := $(R_CROSS_COMPILE) ++KVER:= 3.4.0 ++#KSRC := ../../../../build/out/kernel ++KSRC := $(KERNEL_BUILD_PATH) ++MODULE_NAME :=wlan ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ACTIONS_ATM705X), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++#EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC ++# default setting for Android 4.1, 4.2, 4.3, 4.4 ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_ACTIONS_ATM705X ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++ ++# Enable this for Android 5.0 ++EXTRA_CFLAGS += -DCONFIG_RADIO_WORK ++ ++ifeq ($(CONFIG_SDIO_HCI), y) ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS ++_PLATFORM_FILES += platform/platform_arm_act_sdio.o ++endif ++ ++ARCH := arm ++CROSS_COMPILE := /opt/arm-2011.09/bin/arm-none-linux-gnueabi- ++KSRC := /home/android_sdk/Action-semi/705a_android_L/android/kernel ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_SUN50IW1P1), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN50IW1P1 ++EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT ++# default setting for Android 4.1, 4.2 ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++EXTRA_CFLAGS += -DCONFIG_RESUME_IN_WORKQUEUE ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS ++ ++# Enable this for Android 5.0 ++EXTRA_CFLAGS += -DCONFIG_RADIO_WORK ++ ++ifeq ($(CONFIG_USB_HCI), y) ++EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX ++_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o ++endif ++ifeq ($(CONFIG_SDIO_HCI), y) ++_PLATFORM_FILES += platform/platform_ARM_SUN50IW1P1_sdio.o ++endif ++ ++ARCH := arm64 ++# ===Cross compile setting for Android 5.1(64) SDK === ++CROSS_COMPILE := /home/android_sdk/Allwinner/a64/android-51/lichee/out/sun50iw1p1/android/common/buildroot/external-toolchain/bin/aarch64-linux-gnu- ++KSRC :=/home/android_sdk/Allwinner/a64/android-51/lichee/linux-3.10/ ++endif ++ ++ifeq ($(CONFIG_PLATFORM_TI_AM3517), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -DCONFIG_PLATFORM_SHUTTLE ++CROSS_COMPILE := arm-eabi- ++KSRC := $(shell pwd)/../../../Android/kernel ++ARCH := arm ++endif ++ ++ifeq ($(CONFIG_PLATFORM_MSTAR_TITANIA12), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MSTAR -DCONFIG_PLATFORM_MSTAR_TITANIA12 ++ARCH:=mips ++CROSS_COMPILE:= /usr/src/Mstar_kernel/mips-4.3/bin/mips-linux-gnu- ++KVER:= 2.6.28.9 ++KSRC:= /usr/src/Mstar_kernel/2.6.28.9/ ++endif ++ ++ifeq ($(CONFIG_PLATFORM_MSTAR), y) ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_MSTAR ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_MSTAR_HIGH ++ifeq ($(CONFIG_USB_HCI), y) ++EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX -DCONFIG_FIX_NR_BULKIN_BUFFER ++endif ++ARCH:=arm ++CROSS_COMPILE:= /usr/src/bin/arm-none-linux-gnueabi- ++KVER:= 3.1.10 ++KSRC:= /usr/src/Mstar_kernel/3.1.10/ ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ANDROID_ARM64), y) ++# For this to work, change the "modules:" section is also needed, in order to build with CLANG. ++# "$(MAKE) ARCH=$(ARCH) SUBARCH=$(ARCH) REAL_CC=${CC_DIR}/clang CLANG_TRIPLE=aarch64-linux-gnu- CROSS_COMPILE=$(CROSS_COMPILE) -C $(KSRC) M=$(shell pwd) O="$(KBUILD_OUTPUT)" modules" ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -fno-pic ++EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC -DCONFIG_RADIO_WORK ++#Enable this to have two interfaces: ++#EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++EXTRA_CFLAGS += -DCONFIG_P2P_IPS ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ANDROID_X86), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++SUBARCH := $(shell uname -m | sed -e s/i.86/i386/) ++ARCH := $(SUBARCH) ++CROSS_COMPILE := /media/DATA-2/android-x86/ics-x86_20120130/prebuilt/linux-x86/toolchain/i686-unknown-linux-gnu-4.2.1/bin/i686-unknown-linux-gnu- ++KSRC := /media/DATA-2/android-x86/ics-x86_20120130/out/target/product/generic_x86/obj/kernel ++MODULE_NAME :=wlan ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ANDROID_INTEL_X86), y) ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_ANDROID_INTEL_X86 ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_INTEL_BYT ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++EXTRA_CFLAGS += -DCONFIG_SKIP_SIGNAL_SCALE_MAPPING ++ifeq ($(CONFIG_SDIO_HCI), y) ++EXTRA_CFLAGS += -DCONFIG_RESUME_IN_WORKQUEUE ++endif ++endif ++ ++ifeq ($(CONFIG_PLATFORM_JB_X86), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++SUBARCH := $(shell uname -m | sed -e s/i.86/i386/) ++ARCH := $(SUBARCH) ++CROSS_COMPILE := /home/android_sdk/android-x86_JB/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7/bin/i686-linux-android- ++KSRC := /home/android_sdk/android-x86_JB/out/target/product/x86/obj/kernel/ ++MODULE_NAME :=wlan ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_PXA2XX), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++ARCH := arm ++CROSS_COMPILE := arm-none-linux-gnueabi- ++KVER := 2.6.34.1 ++KSRC ?= /usr/src/linux-2.6.34.1 ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_S3C2K4), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++ARCH := arm ++CROSS_COMPILE := arm-linux- ++KVER := 2.6.24.7_$(ARCH) ++KSRC := /usr/src/kernels/linux-$(KVER) ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_S3C6K4), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++ARCH := arm ++CROSS_COMPILE := arm-none-linux-gnueabi- ++KVER := 2.6.34.1 ++KSRC ?= /usr/src/linux-2.6.34.1 ++endif ++ ++ifeq ($(CONFIG_PLATFORM_RTD2880B), y) ++EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN -DCONFIG_PLATFORM_RTD2880B ++ARCH:= ++CROSS_COMPILE:= ++KVER:= ++KSRC:= ++endif ++ ++ifeq ($(CONFIG_PLATFORM_MIPS_RMI), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++ARCH:=mips ++CROSS_COMPILE:=mipsisa32r2-uclibc- ++KVER:= ++KSRC:= /root/work/kernel_realtek ++endif ++ ++ifeq ($(CONFIG_PLATFORM_MIPS_PLM), y) ++EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN ++ARCH:=mips ++CROSS_COMPILE:=mipsisa32r2-uclibc- ++KVER:= ++KSRC:= /root/work/kernel_realtek ++endif ++ ++ifeq ($(CONFIG_PLATFORM_MSTAR389), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MSTAR389 ++ARCH:=mips ++CROSS_COMPILE:= mips-linux-gnu- ++KVER:= 2.6.28.10 ++KSRC:= /home/mstar/mstar_linux/2.6.28.9/ ++endif ++ ++ifeq ($(CONFIG_PLATFORM_MIPS_AR9132), y) ++EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN ++ARCH := mips ++CROSS_COMPILE := mips-openwrt-linux- ++KSRC := /home/alex/test_openwrt/tmp/linux-2.6.30.9 ++endif ++ ++# This is how I built for openwrt Neo2 platform. --Ben ++ifeq ($(CONFIG_PLATFORM_OPENWRT_NEO2), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++ARCH := arm64 ++CROSS_COMPILE := aarch64-openwrt-linux- ++#export PATH=$PATH:/home/greearb/git/openwrt-neo2-dev/staging_dir/toolchain-aarch64_cortex-a53_gcc-7.3.0_musl/bin/ ++#export STAGING_DIR=/home/greearb/git/openwrt-neo2-dev/staging_dir ++KSRC := /home/greearb/git/openwrt-neo2-dev/build_dir/target-aarch64_cortex-a53_musl/linux-sunxi_cortexa53/linux-4.14.78 ++endif ++ ++ifeq ($(CONFIG_PLATFORM_DMP_PHILIPS), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DRTK_DMP_PLATFORM ++ARCH := mips ++#CROSS_COMPILE:=/usr/local/msdk-4.3.6-mips-EL-2.6.12.6-0.9.30.3/bin/mipsel-linux- ++CROSS_COMPILE:=/usr/local/toolchain_mipsel/bin/mipsel-linux- ++KSRC ?=/usr/local/Jupiter/linux-2.6.12 ++endif ++ ++ifeq ($(CONFIG_PLATFORM_RTK_DMP), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DRTK_DMP_PLATFORM -DCONFIG_WIRELESS_EXT ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS ++ifeq ($(CONFIG_USB_HCI), y) ++_PLATFORM_FILES += platform/platform_RTK_DMP_usb.o ++endif ++ARCH:=mips ++CROSS_COMPILE:=mipsel-linux- ++KVER:= ++KSRC ?= /usr/src/DMP_Kernel/jupiter/linux-2.6.12 ++endif ++ ++ifeq ($(CONFIG_PLATFORM_MT53XX), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MT53XX ++ARCH:= arm ++CROSS_COMPILE:= arm11_mtk_le- ++KVER:= 2.6.27 ++KSRC?= /proj/mtk00802/BD_Compare/BDP/Dev/BDP_V301/BDP_Linux/linux-2.6.27 ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_MX51_241H), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_WISTRON_PLATFORM ++ARCH := arm ++CROSS_COMPILE := /opt/freescale/usr/local/gcc-4.1.2-glibc-2.5-nptl-3/arm-none-linux-gnueabi/bin/arm-none-linux-gnueabi- ++KVER := 2.6.31 ++KSRC ?= /lib/modules/2.6.31-770-g0e46b52/source ++endif ++ ++ifeq ($(CONFIG_PLATFORM_FS_MX61), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++ARCH := arm ++CROSS_COMPILE ?= ++KVER ?= $(shell uname -r) ++KSRC := /lib/modules/$(KVER)/build ++MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/ ++INSTALL_PREFIX := ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ACTIONS_ATJ227X), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ACTIONS_ATJ227X ++ARCH := mips ++CROSS_COMPILE := /home/cnsd4/project/actions/tools-2.6.27/bin/mipsel-linux-gnu- ++KVER := 2.6.27 ++KSRC := /home/cnsd4/project/actions/linux-2.6.27.28 ++endif ++ ++ifeq ($(CONFIG_PLATFORM_TI_DM365), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_TI_DM365 ++EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_RX ++EXTRA_CFLAGS += -DCONFIG_SINGLE_XMIT_BUF -DCONFIG_SINGLE_RECV_BUF ++ARCH := arm ++#CROSS_COMPILE := /home/cnsd4/Appro/mv_pro_5.0/montavista/pro/devkit/arm/v5t_le/bin/arm_v5t_le- ++#KSRC := /home/cnsd4/Appro/mv_pro_5.0/montavista/pro/devkit/lsp/ti-davinci/linux-dm365 ++CROSS_COMPILE := /opt/montavista/pro5.0/devkit/arm/v5t_le/bin/arm-linux- ++KSRC:= /home/vivotek/lsp/DM365/kernel_platform/kernel/linux-2.6.18 ++KERNELOUTPUT := ${PRODUCTDIR}/tmp ++KVER := 2.6.18 ++endif ++ ++ifeq ($(CONFIG_PLATFORM_MOZART), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MOZART ++ARCH := arm ++CROSS_COMPILE := /home/vivotek/lsp/mozart3v2/Mozart3e_Toolchain/build_arm_nofpu/usr/bin/arm-linux- ++KVER := $(shell uname -r) ++KSRC:= /opt/Vivotek/lsp/mozart3v2/kernel_platform/kernel/mozart_kernel-1.17 ++KERNELOUTPUT := /home/pink/sample/ODM/IP8136W-VINT/tmp/kernel ++endif ++ ++ifeq ($(CONFIG_PLATFORM_TEGRA3_CARDHU), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++# default setting for Android 4.1, 4.2 ++EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++ARCH := arm ++CROSS_COMPILE := /home/android_sdk/nvidia/tegra-16r3-partner-android-4.1_20120723/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi- ++KSRC := /home/android_sdk/nvidia/tegra-16r3-partner-android-4.1_20120723/out/target/product/cardhu/obj/KERNEL ++MODULE_NAME := wlan ++endif ++ ++ifeq ($(CONFIG_PLATFORM_TEGRA4_DALMORE), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++# default setting for Android 4.1, 4.2 ++EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++ARCH := arm ++CROSS_COMPILE := /home/android_sdk/nvidia/tegra-17r9-partner-android-4.2-dalmore_20130131/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi- ++KSRC := /home/android_sdk/nvidia/tegra-17r9-partner-android-4.2-dalmore_20130131/out/target/product/dalmore/obj/KERNEL ++MODULE_NAME := wlan ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_TCC8900), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++ARCH := arm ++CROSS_COMPILE := /home/android_sdk/Telechips/SDK_2304_20110613/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi- ++KSRC := /home/android_sdk/Telechips/SDK_2304_20110613/kernel ++MODULE_NAME := wlan ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_TCC8920), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++ARCH := arm ++CROSS_COMPILE := /home/android_sdk/Telechips/v12.06_r1-tcc-android-4.0.4/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi- ++KSRC := /home/android_sdk/Telechips/v12.06_r1-tcc-android-4.0.4/kernel ++MODULE_NAME := wlan ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_TCC8920_JB42), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++# default setting for Android 4.1, 4.2 ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++ARCH := arm ++CROSS_COMPILE := /home/android_sdk/Telechips/v13.03_r1-tcc-android-4.2.2_ds_patched/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi- ++KSRC := /home/android_sdk/Telechips/v13.03_r1-tcc-android-4.2.2_ds_patched/kernel ++MODULE_NAME := wlan ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_RK2818), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -DCONFIG_PLATFORM_ROCKCHIPS ++ARCH := arm ++CROSS_COMPILE := /usr/src/release_fae_version/toolchain/arm-eabi-4.4.0/bin/arm-eabi- ++KSRC := /usr/src/release_fae_version/kernel25_A7_281x ++MODULE_NAME := wlan ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_RK3188), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -DCONFIG_PLATFORM_ROCKCHIPS ++# default setting for Android 4.1, 4.2, 4.3, 4.4 ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++# default setting for Power control ++EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC ++EXTRA_CFLAGS += -DRTW_SUPPORT_PLATFORM_SHUTDOWN ++# default setting for Special function ++ARCH := arm ++CROSS_COMPILE := /home/android_sdk/Rockchip/Rk3188/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi- ++KSRC := /home/android_sdk/Rockchip/Rk3188/kernel ++MODULE_NAME := wlan ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_RK3066), y) ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_RK3066 ++EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 ++ifeq ($(CONFIG_SDIO_HCI), y) ++EXTRA_CFLAGS += -DRTW_SUPPORT_PLATFORM_SHUTDOWN ++endif ++EXTRA_CFLAGS += -fno-pic ++ARCH := arm ++CROSS_COMPILE := /home/android_sdk/Rockchip/rk3066_20130607/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.6/bin/arm-linux-androideabi- ++#CROSS_COMPILE := /home/android_sdk/Rockchip/Rk3066sdk/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.6/bin/arm-linux-androideabi- ++KSRC := /home/android_sdk/Rockchip/Rk3066sdk/kernel ++MODULE_NAME :=wlan ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_URBETTER), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN #-DCONFIG_MINIMAL_MEMORY_USAGE ++ARCH := arm ++CROSS_COMPILE := /media/DATA-1/urbetter/arm-2009q3/bin/arm-none-linux-gnueabi- ++KSRC := /media/DATA-1/urbetter/ics-urbetter/kernel ++MODULE_NAME := wlan ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_TI_PANDA), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN #-DCONFIG_MINIMAL_MEMORY_USAGE ++ARCH := arm ++#CROSS_COMPILE := /media/DATA-1/aosp/ics-aosp_20111227/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi- ++#KSRC := /media/DATA-1/aosp/android-omap-panda-3.0_20120104 ++CROSS_COMPILE := /media/DATA-1/android-4.0/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi- ++KSRC := /media/DATA-1/android-4.0/panda_kernel/omap ++MODULE_NAME := wlan ++endif ++ ++ifeq ($(CONFIG_PLATFORM_MIPS_JZ4760), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_MINIMAL_MEMORY_USAGE ++ARCH ?= mips ++CROSS_COMPILE ?= /mnt/sdb5/Ingenic/Umido/mips-4.3/bin/mips-linux-gnu- ++KSRC ?= /mnt/sdb5/Ingenic/Umido/kernel ++endif ++ ++ifeq ($(CONFIG_PLATFORM_SZEBOOK), y) ++EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN ++ARCH:=arm ++CROSS_COMPILE:=/opt/crosstool2/bin/armeb-unknown-linux-gnueabi- ++KVER:= 2.6.31.6 ++KSRC:= ../code/linux-2.6.31.6-2020/ ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_SUNxI), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUNxI ++# default setting for Android 4.1, 4.2 ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++ ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS ++ifeq ($(CONFIG_USB_HCI), y) ++EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX ++_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o ++endif ++ifeq ($(CONFIG_SDIO_HCI), y) ++# default setting for A10-EVB mmc0 ++#EXTRA_CFLAGS += -DCONFIG_WITS_EVB_V13 ++_PLATFORM_FILES += platform/platform_ARM_SUNxI_sdio.o ++endif ++ ++ARCH := arm ++#CROSS_COMPILE := arm-none-linux-gnueabi- ++CROSS_COMPILE=/home/android_sdk/Allwinner/a10/android-jb42/lichee-jb42/buildroot/output/external-toolchain/bin/arm-none-linux-gnueabi- ++KVER := 3.0.8 ++#KSRC:= ../lichee/linux-3.0/ ++KSRC=/home/android_sdk/Allwinner/a10/android-jb42/lichee-jb42/linux-3.0 ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_SUN6I), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN6I ++EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT ++# default setting for Android 4.1, 4.2, 4.3, 4.4 ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++EXTRA_CFLAGS += -DCONFIG_QOS_OPTIMIZATION ++ ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS ++ifeq ($(CONFIG_USB_HCI), y) ++EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX ++_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o ++endif ++ifeq ($(CONFIG_SDIO_HCI), y) ++# default setting for A31-EVB mmc0 ++EXTRA_CFLAGS += -DCONFIG_A31_EVB ++_PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o ++endif ++ ++ARCH := arm ++#Android-JB42 ++#CROSS_COMPILE := /home/android_sdk/Allwinner/a31/android-jb42/lichee/buildroot/output/external-toolchain/bin/arm-linux-gnueabi- ++#KSRC :=/home/android_sdk/Allwinner/a31/android-jb42/lichee/linux-3.3 ++#ifeq ($(CONFIG_USB_HCI), y) ++#MODULE_NAME := 8188eu_sw ++#endif ++# ==== Cross compile setting for kitkat-a3x_v4.5 ===== ++CROSS_COMPILE := /home/android_sdk/Allwinner/a31/kitkat-a3x_v4.5/lichee/buildroot/output/external-toolchain/bin/arm-linux-gnueabi- ++KSRC :=/home/android_sdk/Allwinner/a31/kitkat-a3x_v4.5/lichee/linux-3.3 ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_SUN7I), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN7I ++EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT ++# default setting for Android 4.1, 4.2, 4.3, 4.4 ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++EXTRA_CFLAGS += -DCONFIG_QOS_OPTIMIZATION ++ ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS ++ifeq ($(CONFIG_USB_HCI), y) ++EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX ++_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o ++endif ++ifeq ($(CONFIG_SDIO_HCI), y) ++_PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o ++endif ++ ++ARCH := arm ++# ===Cross compile setting for Android 4.2 SDK === ++#CROSS_COMPILE := /home/android_sdk/Allwinner/a20_evb/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi- ++#KSRC := /home/android_sdk/Allwinner/a20_evb/lichee/linux-3.3 ++# ==== Cross compile setting for Android 4.3 SDK ===== ++#CROSS_COMPILE := /home/android_sdk/Allwinner/a20/android-jb43/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi- ++#KSRC := /home/android_sdk/Allwinner/a20/android-jb43/lichee/linux-3.4 ++# ==== Cross compile setting for kitkat-a20_v4.4 ===== ++CROSS_COMPILE := /home/android_sdk/Allwinner/a20/kitkat-a20_v4.4/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi- ++KSRC := /home/android_sdk/Allwinner/a20/kitkat-a20_v4.4/lichee/linux-3.4 ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_SUN8I_W3P1), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN8I ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN8I_W3P1 ++EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT ++# default setting for Android 4.1, 4.2 ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++ ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS ++ifeq ($(CONFIG_USB_HCI), y) ++EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX ++_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o ++endif ++ifeq ($(CONFIG_SDIO_HCI), y) ++_PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o ++endif ++ ++ARCH := arm ++# ===Cross compile setting for Android 4.2 SDK === ++#CROSS_COMPILE := /home/android_sdk/Allwinner/a23/android-jb42/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi- ++#KSRC :=/home/android_sdk/Allwinner/a23/android-jb42/lichee/linux-3.4 ++# ===Cross compile setting for Android 4.4 SDK === ++CROSS_COMPILE := /home/android_sdk/Allwinner/a23/android-kk44/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi- ++KSRC :=/home/android_sdk/Allwinner/a23/android-kk44/lichee/linux-3.4 ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_SUN8I_W5P1), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN8I ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN8I_W5P1 ++EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT ++# default setting for Android 4.1, 4.2 ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++ ++# Enable this for Android 5.0 ++EXTRA_CFLAGS += -DCONFIG_RADIO_WORK ++ ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS ++ifeq ($(CONFIG_USB_HCI), y) ++EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX ++_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o ++endif ++ifeq ($(CONFIG_SDIO_HCI), y) ++_PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o ++endif ++ ++ARCH := arm ++# ===Cross compile setting for Android L SDK === ++CROSS_COMPILE := /home/android_sdk/Allwinner/a33/android-L/lichee/out/sun8iw5p1/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi- ++KSRC :=/home/android_sdk/Allwinner/a33/android-L/lichee/linux-3.4 ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ACTIONS_ATV5201), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ACTIONS_ATV5201 ++EXTRA_CFLAGS += -DCONFIG_SDIO_DISABLE_RXFIFO_POLLING_LOOP ++ARCH := mips ++CROSS_COMPILE := mipsel-linux-gnu- ++KVER := $(KERNEL_VER) ++KSRC:= $(CFGDIR)/../../kernel/linux-$(KERNEL_VER) ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_RTD299X), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++ifeq ($(CONFIG_ANDROID), y) ++# Enable this for Android 5.0 ++EXTRA_CFLAGS += -DCONFIG_RADIO_WORK ++endif ++#ARCH, CROSS_COMPILE, KSRC,and MODDESTDIR are provided by external makefile ++INSTALL_PREFIX := ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_RTD299X_LG), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DRTW_P2P_GROUP_INTERFACE=1 ++EXTRA_CFLAGS += -DCONFIG_IFACE_NUMBER=3 ++#EXTRA_CFLAGS += -DCONFIG_FIX_HWPORT ++EXTRA_CFLAGS += -DLGE_PRIVATE ++EXTRA_CFLAGS += -DPURE_SUPPLICANT ++EXTRA_CFLAGS += -DCONFIG_CUSTOMIZED_COUNTRY_CHPLAN_MAP -DCONFIG_RTW_IOCTL_SET_COUNTRY ++EXTRA_CFLAGS += -DDBG_RX_DFRAME_RAW_DATA ++EXTRA_CFLAGS += -DRTW_REDUCE_SCAN_SWITCH_CH_TIME ++ARCH ?= arm ++KVER ?= ++ ++ifneq ($(PLATFORM), WEBOS) ++$(info PLATFORM is empty) ++CROSS_COMPILE ?= /mnt/newdisk/LGE/arm-lg115x-linux-gnueabi-4.8-2016.03-x86_64/bin/arm-lg115x-linux-gnueabi- ++KSRC ?= /mnt/newdisk/LGE/linux-rockhopper_k3lp_drd4tv_423 ++endif ++ ++CROSS_COMPILE ?= ++KSRC ?= $(LINUX_SRC) ++INSTALL_PREFIX ?= ++endif ++ ++ifeq ($(CONFIG_PLATFORM_HISILICON), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_HISILICON ++ifeq ($(SUPPORT_CONCURRENT),y) ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++endif ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++ARCH := arm ++ifeq ($(CROSS_COMPILE),) ++ CROSS_COMPILE = arm-hisiv200-linux- ++endif ++MODULE_NAME := rtl8192eu ++ifeq ($(KSRC),) ++ KSRC := ../../../../../../kernel/linux-3.4.y ++endif ++endif ++ ++ifeq ($(CONFIG_PLATFORM_HISILICON_HI3798), y) ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_HISILICON ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_HISILICON_HI3798 ++#EXTRA_CFLAGS += -DCONFIG_PLATFORM_HISILICON_HI3798_MV200_HDMI_DONGLE ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++# default setting for Android ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 ++EXTRA_CFLAGS += -DRTW_USE_CFG80211_STA_EVENT ++# default setting for Android 5.x and later ++#EXTRA_CFLAGS += -DCONFIG_RADIO_WORK ++ ++# If system could power on and recognize Wi-Fi SDIO automatically, ++# platfrom operations are not necessary. ++#ifeq ($(CONFIG_SDIO_HCI), y) ++#EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS ++#_PLATFORM_FILES += platform/platform_hisilicon_hi3798_sdio.o ++#EXTRA_CFLAGS += -DCONFIG_HISI_SDIO_ID=1 ++#endif ++ ++ARCH ?= arm ++CROSS_COMPILE ?= /HiSTBAndroidV600R003C00SPC021_git_0512/device/hisilicon/bigfish/sdk/tools/linux/toolchains/arm-histbv310-linux/bin/arm-histbv310-linux- ++ifndef KSRC ++KSRC := /HiSTBAndroidV600R003C00SPC021_git_0512/device/hisilicon/bigfish/sdk/source/kernel/linux-3.18.y ++KSRC += O=/HiSTBAndroidV600R003C00SPC021_git_0512/out/target/product/Hi3798MV200/obj/KERNEL_OBJ ++endif ++ ++ifeq ($(CONFIG_RTL8822B), y) ++ifeq ($(CONFIG_SDIO_HCI), y) ++CONFIG_RTL8822BS ?= m ++USER_MODULE_NAME := rtl8822bs ++endif ++endif ++ ++endif ++ ++# Platform setting ++ifeq ($(CONFIG_PLATFORM_ARM_SPREADTRUM_6820), y) ++ifeq ($(CONFIG_ANDROID_2X), y) ++EXTRA_CFLAGS += -DANDROID_2X ++endif ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_SPRD ++EXTRA_CFLAGS += -DPLATFORM_SPREADTRUM_6820 ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++ifeq ($(RTL871X), rtl8188e) ++EXTRA_CFLAGS += -DSOFTAP_PS_DURATION=50 ++endif ++ifeq ($(CONFIG_SDIO_HCI), y) ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS ++_PLATFORM_FILES += platform/platform_sprd_sdio.o ++endif ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_SPREADTRUM_8810), y) ++ifeq ($(CONFIG_ANDROID_2X), y) ++EXTRA_CFLAGS += -DANDROID_2X ++endif ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_SPRD ++EXTRA_CFLAGS += -DPLATFORM_SPREADTRUM_8810 ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++ifeq ($(RTL871X), rtl8188e) ++EXTRA_CFLAGS += -DSOFTAP_PS_DURATION=50 ++endif ++ifeq ($(CONFIG_SDIO_HCI), y) ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS ++_PLATFORM_FILES += platform/platform_sprd_sdio.o ++endif ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_WMT), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS ++ifeq ($(CONFIG_SDIO_HCI), y) ++_PLATFORM_FILES += platform/platform_ARM_WMT_sdio.o ++endif ++ARCH := arm ++CROSS_COMPILE := /home/android_sdk/WonderMedia/wm8880-android4.4/toolchain/arm_201103_gcc4.5.2/mybin/arm_1103_le- ++KSRC := /home/android_sdk/WonderMedia/wm8880-android4.4/kernel4.4/ ++MODULE_NAME :=8189es_kk ++endif ++ ++ifeq ($(CONFIG_PLATFORM_RTK119X), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++#EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN7I ++EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT ++# default setting for Android 4.1, 4.2 ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++#EXTRA_CFLAGS += -DCONFIG_QOS_OPTIMIZATION ++EXTRA_CFLAGS += -DCONFIG_QOS_OPTIMIZATION ++ ++#EXTRA_CFLAGS += -DCONFIG_#PLATFORM_OPS ++ifeq ($(CONFIG_USB_HCI), y) ++EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX ++#_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o ++endif ++ifeq ($(CONFIG_SDIO_HCI), y) ++_PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o ++endif ++ ++ARCH := arm ++ ++# ==== Cross compile setting for Android 4.4 SDK ===== ++#CROSS_COMPILE := arm-linux-gnueabihf- ++KVER := 3.10.24 ++#KSRC :=/home/android_sdk/Allwinner/a20/android-kitkat44/lichee/linux-3.4 ++CROSS_COMPILE := /home/realtek/software_phoenix/phoenix/toolchain/usr/local/arm-2013.11/bin/arm-linux-gnueabihf- ++KSRC := /home/realtek/software_phoenix/linux-kernel ++MODULE_NAME := 8192eu ++ ++endif ++ ++ifeq ($(CONFIG_PLATFORM_RTK119X_AM), y) ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_RTK119X_AM ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE -DCONFIG_FULL_CH_IN_P2P_HANDSHAKE ++EXTRA_CFLAGS += -DCONFIG_IFACE_NUMBER=3 ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++ ++ifeq ($(CONFIG_USB_HCI), y) ++EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX ++endif ++ ++ARCH := arm ++ ++#CROSS_COMPILE := arm-linux-gnueabihf- ++KVER := 3.10.24 ++#KSRC := ++CROSS_COMPILE := ++endif ++ ++ifeq ($(CONFIG_PLATFORM_RTK129X), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++EXTRA_CFLAGS += -DRTK_129X_PLATFORM ++EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT ++# default setting for Android 4.1, 4.2 ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++#EXTRA_CFLAGS += -DCONFIG_P2P_IPS -DCONFIG_QOS_OPTIMIZATION ++EXTRA_CFLAGS += -DCONFIG_QOS_OPTIMIZATION ++# Enable this for Android 5.0 ++EXTRA_CFLAGS += -DCONFIG_RADIO_WORK ++ifeq ($(CONFIG_RTL8821C)$(CONFIG_SDIO_HCI),yy) ++EXTRA_CFLAGS += -DCONFIG_WAKEUP_GPIO_INPUT_MODE ++EXTRA_CFLAGS += -DCONFIG_BT_WAKE_HST_OPEN_DRAIN ++endif ++EXTRA_CFLAGS += -Wno-error=date-time ++# default setting for Android 7.0 ++ifeq ($(RTK_ANDROID_VERSION), nougat) ++EXTRA_CFLAGS += -DRTW_P2P_GROUP_INTERFACE=1 ++endif ++#EXTRA_CFLAGS += -DCONFIG_#PLATFORM_OPS ++ifeq ($(CONFIG_USB_HCI), y) ++EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX ++endif ++ ++ARCH := arm64 ++ ++# ==== Cross compile setting for Android 4.4 SDK ===== ++#CROSS_COMPILE := arm-linux-gnueabihf- ++#KVER := 4.1.10 ++#CROSS_COMPILE := $(CROSS) ++#KSRC := $(LINUX_KERNEL_PATH) ++CROSS_COMPILE := /home/android_sdk/DHC/trunk-6.0.0_r1-QA160627/phoenix/toolchain/asdk64-4.9.4-a53-EL-3.10-g2.19-a64nt-160307/bin/asdk64-linux- ++KSRC := /home/android_sdk/DHC/trunk-6.0.0_r1-QA160627/linux-kernel ++endif ++ ++ifeq ($(CONFIG_PLATFORM_RTK390X), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_RTK390X ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++EXTRA_CFLAGS += -DCONFIG_RTW_NETIF_SG ++ifeq ($(CONFIG_USB_HCI), y) ++EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX ++endif ++ ++ARCH:=rlx ++ ++CROSS_COMPILE:=mips-linux- ++KSRC:= /home/realtek/share/Develop/IPCAM_SDK/RealSil/rts3901_sdk_v1.2_vanilla/linux-3.10 ++ ++endif ++ ++ifeq ($(CONFIG_PLATFORM_NOVATEK_NT72668), y) ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_NOVATEK_NT72668 ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_RX ++EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX ++ARCH ?= arm ++CROSS_COMPILE := arm-linux-gnueabihf- ++KVER := 3.8.0 ++KSRC := /Custom/Novatek/TCL/linux-3.8_header ++#KSRC := $(KERNELDIR) ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_TCC8930_JB42), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++# default setting for Android 4.1, 4.2 ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++ARCH := arm ++CROSS_COMPILE := /home/android_sdk/Telechips/v13.05_r1-tcc-android-4.2.2_tcc893x-evm_build/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi- ++KSRC := /home/android_sdk/Telechips/v13.05_r1-tcc-android-4.2.2_tcc893x-evm_build/kernel ++MODULE_NAME := wlan ++endif ++ ++ifeq ($(CONFIG_PLATFORM_RTL8197D), y) ++EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN -DCONFIG_PLATFORM_RTL8197D ++export DIR_LINUX=$(shell pwd)/../SDK/rlxlinux-sdk321-v50/linux-2.6.30 ++ARCH ?= rlx ++CROSS_COMPILE:= $(DIR_LINUX)/../toolchain/rsdk-1.5.5-5281-EB-2.6.30-0.9.30.3-110714/bin/rsdk-linux- ++KSRC := $(DIR_LINUX) ++endif ++ ++ifeq ($(CONFIG_PLATFORM_AML_S905), y) ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_AML_S905 ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -fno-pic ++# default setting for Android ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 ++EXTRA_CFLAGS += -DRTW_USE_CFG80211_STA_EVENT ++# default setting for Android 5.x and later ++EXTRA_CFLAGS += -DCONFIG_RADIO_WORK ++ ++ifeq ($(CONFIG_SDIO_HCI), y) ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS ++_PLATFORM_FILES += platform/platform_aml_s905_sdio.o ++endif ++ ++ARCH ?= arm64 ++CROSS_COMPILE ?= /4.4_S905L_8822bs_compile/gcc-linaro-aarch64-linux-gnu-4.9-2014.09_linux/bin/aarch64-linux-gnu- ++ifndef KSRC ++KSRC := /4.4_S905L_8822bs_compile/common ++# To locate output files in a separate directory. ++KSRC += O=/4.4_S905L_8822bs_compile/KERNEL_OBJ ++endif ++ ++ifeq ($(CONFIG_RTL8822B), y) ++ifeq ($(CONFIG_SDIO_HCI), y) ++CONFIG_RTL8822BS ?= m ++USER_MODULE_NAME := 8822bs ++endif ++endif ++ ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ZTE_ZX296716), y) ++EXTRA_CFLAGS += -Wno-error=date-time ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_ZTE_ZX296716 ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++# default setting for Android ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 ++EXTRA_CFLAGS += -DRTW_USE_CFG80211_STA_EVENT ++# default setting for Android 5.x and later ++#EXTRA_CFLAGS += -DCONFIG_RADIO_WORK ++ ++ifeq ($(CONFIG_SDIO_HCI), y) ++# mark this temporarily ++#EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS ++#_PLATFORM_FILES += platform/platform_zte_zx296716_sdio.o ++endif ++ ++ARCH ?= arm64 ++CROSS_COMPILE ?= ++KSRC ?= ++ ++ifeq ($(CONFIG_RTL8822B), y) ++ifeq ($(CONFIG_SDIO_HCI), y) ++CONFIG_RTL8822BS ?= m ++USER_MODULE_NAME := 8822bs ++endif ++endif ++ ++endif ++ ++ifeq ($(ARCH), i386) ++EXTRA_CFLAGS += -mhard-float ++EXTRA_CFLAGS += -DMARK_KERNEL_PFU ++else ifeq ($(ARCH), x86_64) ++EXTRA_CFLAGS += -mhard-float ++EXTRA_CFLAGS += -DMARK_KERNEL_PFU ++endif ++ ++########### CUSTOMER ################################ ++ifeq ($(CONFIG_CUSTOMER_HUAWEI_GENERAL), y) ++CONFIG_CUSTOMER_HUAWEI = y ++endif ++ ++ifeq ($(CONFIG_CUSTOMER_HUAWEI), y) ++EXTRA_CFLAGS += -DCONFIG_HUAWEI_PROC ++endif ++ ++ifeq ($(CONFIG_MULTIDRV), y) ++ ++ifeq ($(CONFIG_SDIO_HCI), y) ++MODULE_NAME := rtw_sdio ++endif ++ ++ifeq ($(CONFIG_USB_HCI), y) ++MODULE_NAME := rtw_usb ++endif ++ ++ifeq ($(CONFIG_PCI_HCI), y) ++MODULE_NAME := rtw_pci ++endif ++ ++endif ++ ++USER_MODULE_NAME ?= ++ifneq ($(USER_MODULE_NAME),) ++MODULE_NAME := $(USER_MODULE_NAME) ++endif ++ ++ifneq ($(KERNELRELEASE),) ++ ++########### this part for *.mk ############################ ++include $(src)/hal/phydm/phydm.mk ++ ++########### HAL_RTL8822B ################################# ++ifeq ($(CONFIG_RTL8822B), y) ++include $(src)/rtl8822b.mk ++endif ++ ++########### HAL_RTL8821C ################################# ++ifeq ($(CONFIG_RTL8821C), y) ++include $(src)/rtl8821c.mk ++endif ++ ++rtk_core := core/rtw_cmd.o \ ++ core/rtw_security.o \ ++ core/rtw_debug.o \ ++ core/rtw_io.o \ ++ core/rtw_ioctl_query.o \ ++ core/rtw_ioctl_set.o \ ++ core/rtw_ieee80211.o \ ++ core/rtw_mlme.o \ ++ core/rtw_mlme_ext.o \ ++ core/rtw_mi.o \ ++ core/rtw_wlan_util.o \ ++ core/rtw_vht.o \ ++ core/rtw_pwrctrl.o \ ++ core/rtw_rf.o \ ++ core/rtw_chplan.o \ ++ core/rtw_recv.o \ ++ core/rtw_sta_mgt.o \ ++ core/rtw_ap.o \ ++ core/mesh/rtw_mesh.o \ ++ core/mesh/rtw_mesh_pathtbl.o \ ++ core/mesh/rtw_mesh_hwmp.o \ ++ core/rtw_xmit.o \ ++ core/rtw_p2p.o \ ++ core/rtw_rson.o \ ++ core/rtw_tdls.o \ ++ core/rtw_br_ext.o \ ++ core/rtw_iol.o \ ++ core/rtw_sreset.o \ ++ core/rtw_btcoex_wifionly.o \ ++ core/rtw_btcoex.o \ ++ core/rtw_beamforming.o \ ++ core/rtw_odm.o \ ++ core/rtw_rm.o \ ++ core/rtw_rm_fsm.o \ ++ core/efuse/rtw_efuse.o ++ ++ifeq ($(CONFIG_SDIO_HCI), y) ++rtk_core += core/rtw_sdio.o ++endif ++ ++$(MODULE_NAME)-y += $(rtk_core) ++ ++$(MODULE_NAME)-$(CONFIG_INTEL_WIDI) += core/rtw_intel_widi.o ++ ++$(MODULE_NAME)-$(CONFIG_WAPI_SUPPORT) += core/rtw_wapi.o \ ++ core/rtw_wapi_sms4.o ++ ++$(MODULE_NAME)-y += $(_OS_INTFS_FILES) ++$(MODULE_NAME)-y += $(_HAL_INTFS_FILES) ++$(MODULE_NAME)-y += $(_PHYDM_FILES) ++$(MODULE_NAME)-y += $(_BTC_FILES) ++$(MODULE_NAME)-y += $(_PLATFORM_FILES) ++ ++$(MODULE_NAME)-$(CONFIG_MP_INCLUDED) += core/rtw_mp.o ++ ++obj-$(CONFIG_88XXAU) := $(MODULE_NAME).o ++ ++else ++ ++export CONFIG_88XXAU = m ++ ++all: modules ++ ++modules: ++ $(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KSRC) M=$(shell pwd) modules ++ @echo "---------------------------------------------------------------------------" ++ @echo "Visit https://github.com/aircrack-ng/rtl8812au for support/reporting issues" ++ @echo "or check for newer versions (branches) of these drivers. " ++ @echo "---------------------------------------------------------------------------" ++strip: ++ $(CROSS_COMPILE)strip $(MODULE_NAME).ko --strip-unneeded ++ ++install: ++ install -p -m 644 $(MODULE_NAME).ko $(MODDESTDIR) ++ /sbin/depmod -a ${KVER} ++ ++uninstall: ++ rm -f $(MODDESTDIR)/$(MODULE_NAME).ko ++ /sbin/depmod -a ${KVER} ++ ++backup_rtlwifi: ++ @echo "Making backup rtlwifi drivers" ++ifneq (,$(wildcard $(STAGINGMODDIR)/rtl*)) ++ @tar cPf $(wildcard $(STAGINGMODDIR))/backup_rtlwifi_driver.tar $(wildcard $(STAGINGMODDIR)/rtl*) ++ @rm -rf $(wildcard $(STAGINGMODDIR)/rtl*) ++endif ++ifneq (,$(wildcard $(MODDESTDIR)realtek)) ++ @tar cPf $(MODDESTDIR)backup_rtlwifi_driver.tar $(MODDESTDIR)realtek ++ @rm -fr $(MODDESTDIR)realtek ++endif ++ifneq (,$(wildcard $(MODDESTDIR)rtl*)) ++ @tar cPf $(MODDESTDIR)../backup_rtlwifi_driver.tar $(wildcard $(MODDESTDIR)rtl*) ++ @rm -fr $(wildcard $(MODDESTDIR)rtl*) ++endif ++ @/sbin/depmod -a ${KVER} ++ @echo "Please reboot your system" ++ ++restore_rtlwifi: ++ @echo "Restoring backups" ++ifneq (,$(wildcard $(STAGINGMODDIR)/backup_rtlwifi_driver.tar)) ++ @tar xPf $(STAGINGMODDIR)/backup_rtlwifi_driver.tar ++ @rm $(STAGINGMODDIR)/backup_rtlwifi_driver.tar ++endif ++ifneq (,$(wildcard $(MODDESTDIR)backup_rtlwifi_driver.tar)) ++ @tar xPf $(MODDESTDIR)backup_rtlwifi_driver.tar ++ @rm $(MODDESTDIR)backup_rtlwifi_driver.tar ++endif ++ifneq (,$(wildcard $(MODDESTDIR)../backup_rtlwifi_driver.tar)) ++ @tar xPf $(MODDESTDIR)../backup_rtlwifi_driver.tar ++ @rm $(MODDESTDIR)../backup_rtlwifi_driver.tar ++endif ++ @/sbin/depmod -a ${KVER} ++ @echo "Please reboot your system" ++ ++config_r: ++ @echo "make config" ++ /bin/bash script/Configure script/config.in ++ ++DRIVER_VERSION = $(shell grep "\#define DRIVERVERSION" include/rtw_version.h | awk '{print $$3}' | tr -d v\") ++ ++dkms_install: ++ mkdir -p /usr/src/8812au-$(DRIVER_VERSION) ++ cp -r * /usr/src/8812au-$(DRIVER_VERSION) ++ dkms add -m 8812au -v $(DRIVER_VERSION) ++ dkms build -m 8812au -v $(DRIVER_VERSION) ++ dkms install -m 8812au -v $(DRIVER_VERSION) ++ dkms status ++ ++dkms_remove: ++ dkms remove 8812au/$(DRIVER_VERSION) --all ++ rm -rf /usr/src/8812au-$(DRIVER_VERSION) ++ ++.PHONY: modules clean ++ ++clean: ++ #$(MAKE) -C $(KSRC) M=$(shell pwd) clean ++ cd hal ; rm -fr */*/*/*.mod.c */*/*/*.mod */*/*/*.o */*/*/.*.cmd */*/*/*.ko ++ cd hal ; rm -fr */*/*.mod.c */*/*.mod */*/*.o */*/.*.cmd */*/*.ko ++ cd hal ; rm -fr */*.mod.c */*.mod */*.o */.*.cmd */*.ko ++ cd hal ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko ++ cd core ; rm -fr */*.mod.c */*.mod */*.o */.*.cmd */*.ko ++ cd core ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko ++ cd os_dep/linux ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko *.o.d ++ cd os_dep ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko ++ cd platform ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko ++ rm -fr Module.symvers ; rm -fr Module.markers ; rm -fr modules.order ++ rm -fr *.mod.c *.mod *.o .*.cmd *.ko *~ ++ rm -fr .tmp_versions ++endif +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/custom_gpio_linux.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/custom_gpio_linux.c +--- linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/custom_gpio_linux.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/custom_gpio_linux.c 2021-03-07 18:16:17.092957849 +0200 @@ -0,0 +1,340 @@ +/****************************************************************************** + * @@ -416287,12 +414963,10 @@ index 000000000..23401b7d6 +{ +} +#endif /* CONFIG_PLATFORM_SPRD */ -diff --git linux-5.8/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c linux-5.8/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c -new file mode 100644 -index 000000000..8c674fa7b ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c -@@ -0,0 +1,10395 @@ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c +--- linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c 2021-03-07 18:16:17.093957896 +0200 +@@ -0,0 +1,10531 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -416496,9 +415170,14 @@ index 000000000..8c674fa7b + +/* from center_ch_5g_20m */ +static struct ieee80211_channel rtw_5ghz_a_channels[MAX_CHANNEL_NUM_5G] = { ++ CHAN5G(15, 0), CHAN5G(16, 0), CHAN5G(17, 0), CHAN5G(18, 0), ++ CHAN5G(20, 0), CHAN5G(24, 0), CHAN5G(28, 0), CHAN5G(32, 0), ++ + CHAN5G(36, 0), CHAN5G(40, 0), CHAN5G(44, 0), CHAN5G(48, 0), + + CHAN5G(52, 0), CHAN5G(56, 0), CHAN5G(60, 0), CHAN5G(64, 0), ++ CHAN5G(68, 0), CHAN5G(72, 0), CHAN5G(76, 0), CHAN5G(80, 0), ++ CHAN5G(84, 0), CHAN5G(88, 0), CHAN5G(92, 0), CHAN5G(96, 0), + + CHAN5G(100, 0), CHAN5G(104, 0), CHAN5G(108, 0), CHAN5G(112, 0), + CHAN5G(116, 0), CHAN5G(120, 0), CHAN5G(124, 0), CHAN5G(128, 0), @@ -416750,7 +415429,11 @@ index 000000000..8c674fa7b + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) + if (started) { ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)) ++ cfg80211_ch_switch_started_notify(adapter->pnetdev, &chdef, 0, false); ++#else + cfg80211_ch_switch_started_notify(adapter->pnetdev, &chdef, 0); ++#endif + goto exit; + } +#endif @@ -422376,6 +421059,132 @@ index 000000000..8c674fa7b + return 0; +} + ++static int cfg80211_rtw_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev, struct cfg80211_chan_def *chandef){ ++ _adapter *padapter= wiphy_to_adapter(wiphy); ++ int channel; ++ int control_freq; ++ int center_freq; ++ int center_freq2=0; ++ int width; ++ int band; ++ int bandWidth; ++ int offset; ++ ++ struct dvobj_priv *dvobj; ++ struct net_device *ndev = wdev->netdev; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ ++ if (!ndev) ++ return -ENODEV; ++ offset = rtw_get_oper_choffset(padapter); ++ //channel = adapter_to_dvobj(padapter)->oper_channel; ++ channel = pHalData->current_channel; ++ if(channel >= 1){ ++ if(channel <= 14) ++ band = NL80211_BAND_2GHZ; ++ else ++ band = NL80211_BAND_5GHZ; ++#if 0 ++ switch(pHalData->current_band_type){ ++ case 0: ++ band = NL80211_BAND_2GHZ; ++ break; ++ case 1: ++ band = NL80211_BAND_5GHZ; ++ break; ++ default: ++ return -EINVAL; ++ } ++#endif ++ control_freq = ieee80211_channel_to_frequency(channel, band); ++ ++ dvobj = adapter_to_dvobj(padapter); ++ if(dvobj != NULL){ ++ bandWidth = adapter_to_dvobj(padapter)->oper_bwmode; ++ RTW_INFO("%s bw %d\n", __func__, adapter_to_dvobj(padapter)->oper_bwmode); ++ }else{ ++ bandWidth = pHalData->current_channel_bw; ++ RTW_INFO("%s dvobj null\n", __func__); ++ } ++ switch(pHalData->current_channel_bw){ ++ case CHANNEL_WIDTH_5: ++ width = NL80211_CHAN_WIDTH_5; ++ center_freq = control_freq; ++ break; ++ case CHANNEL_WIDTH_10: ++ width = NL80211_CHAN_WIDTH_10; ++ center_freq = control_freq; ++ break; ++ case CHANNEL_WIDTH_20: ++ RTW_INFO("%s width 20\n", __func__); ++ width = NL80211_CHAN_WIDTH_20; ++ center_freq = control_freq; ++ break; ++ case CHANNEL_WIDTH_40: ++ RTW_INFO("%s width 40\n", __func__); ++ width = NL80211_CHAN_WIDTH_40; ++ if(offset == HAL_PRIME_CHNL_OFFSET_LOWER){ ++ center_freq = control_freq +10; ++ }else{ ++ center_freq = control_freq -10; ++ } ++ break; ++ case CHANNEL_WIDTH_80: ++ RTW_INFO("%s width 80\n", __func__); ++ width = NL80211_CHAN_WIDTH_80; ++ if(offset==HAL_PRIME_CHNL_OFFSET_LOWER){ ++ center_freq = control_freq +30; ++ }else{ ++ center_freq = control_freq -30; ++ } ++ break; ++ case CHANNEL_WIDTH_160: ++ RTW_INFO("%s width 160\n", __func__); ++ width = NL80211_CHAN_WIDTH_160; ++ if(offset == HAL_PRIME_CHNL_OFFSET_LOWER){ ++ center_freq = control_freq +50; ++ }else{ ++ center_freq = control_freq -50; ++ } ++ break; ++ case CHANNEL_WIDTH_80_80: ++ RTW_INFO("%s width 80x80\n", __func__); ++ width = NL80211_CHAN_WIDTH_80P80; ++ if(offset==HAL_PRIME_CHNL_OFFSET_LOWER){ ++ center_freq = control_freq +30; ++ center_freq2=center_freq+80; ++ }else{ ++ center_freq = control_freq -30; ++ center_freq2=center_freq-80; ++ } ++ break; ++ case CHANNEL_WIDTH_MAX: ++ RTW_INFO("%s width max\n", __func__); ++ width = NL80211_CHAN_WIDTH_160; ++ break; ++ } ++ chandef->chan = ieee80211_get_channel(wiphy, control_freq); ++ if(chandef->chan == NULL) { ++ chandef->chan = ieee80211_get_channel(wiphy, ieee80211_channel_to_frequency(channel, band)); ++ RTW_INFO("%s chan null\n", __func__); ++ if(chandef->chan == NULL) { ++ RTW_INFO("%s chan null\n", __func__); ++ return -EINVAL; ++ } ++ } ++ chandef->width = width; ++ chandef->center_freq1 = center_freq; ++ chandef->center_freq2 = center_freq2; ++ RTW_INFO("%s : channel %d width %d freq1 %d freq2 %d center_freq %d offset %d\n", __func__, ++ channel, width, chandef->center_freq1, chandef->center_freq2, chandef->chan->center_freq, ++ rtw_get_oper_choffset(padapter) ++ ); ++ }else{ ++ return -EINVAL; ++ } ++ return 0; ++} ++ +static int cfg80211_rtw_set_monitor_channel(struct wiphy *wiphy +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) + , struct cfg80211_chan_def *chandef @@ -426374,6 +425183,7 @@ index 000000000..8c674fa7b +#if (KERNEL_VERSION(4, 17, 0) <= LINUX_VERSION_CODE) + .external_auth = cfg80211_rtw_external_auth, +#endif ++ .get_channel = cfg80211_rtw_get_channel, +}; + +struct wiphy *rtw_wiphy_alloc(_adapter *padapter, struct device *dev) @@ -426688,11 +425498,9 @@ index 000000000..8c674fa7b +} + +#endif /* CONFIG_IOCTL_CFG80211 */ -diff --git linux-5.8/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.h linux-5.8/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.h -new file mode 100644 -index 000000000..e7dd8050e ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.h +--- linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.h 2021-03-07 18:16:17.093957896 +0200 @@ -0,0 +1,427 @@ +/****************************************************************************** + * @@ -427121,11 +425929,9 @@ index 000000000..e7dd8050e + + +#endif /* __IOCTL_CFG80211_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.8/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c -new file mode 100644 -index 000000000..b5b911904 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c +--- linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c 2021-03-07 18:16:17.095957991 +0200 @@ -0,0 +1,12876 @@ + +/****************************************************************************** @@ -440003,11 +438809,9 @@ index 000000000..b5b911904 + return ret; +} + -diff --git linux-5.8/3rdparty/rtl8812au/os_dep/linux/ioctl_mp.c linux-5.8/3rdparty/rtl8812au/os_dep/linux/ioctl_mp.c -new file mode 100644 -index 000000000..a459afb11 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/os_dep/linux/ioctl_mp.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_mp.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/ioctl_mp.c +--- linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_mp.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/ioctl_mp.c 2021-03-07 18:16:17.095957991 +0200 @@ -0,0 +1,2591 @@ +/****************************************************************************** + * @@ -442600,11 +441404,9 @@ index 000000000..a459afb11 +#endif /*#ifdef CONFIG_RTL8723B*/ + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/os_dep/linux/mlme_linux.c linux-5.8/3rdparty/rtl8812au/os_dep/linux/mlme_linux.c -new file mode 100644 -index 000000000..247e45e57 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/os_dep/linux/mlme_linux.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/mlme_linux.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/mlme_linux.c +--- linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/mlme_linux.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/mlme_linux.c 2021-03-07 18:16:17.095957991 +0200 @@ -0,0 +1,436 @@ +/****************************************************************************** + * @@ -443042,12 +441844,10 @@ index 000000000..247e45e57 + +#endif +#endif -diff --git linux-5.8/3rdparty/rtl8812au/os_dep/linux/os_intfs.c linux-5.8/3rdparty/rtl8812au/os_dep/linux/os_intfs.c -new file mode 100644 -index 000000000..1085d6cde ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/os_dep/linux/os_intfs.c -@@ -0,0 +1,5243 @@ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/os_intfs.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/os_intfs.c +--- linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/os_intfs.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/os_intfs.c 2021-03-07 18:16:17.096958038 +0200 +@@ -0,0 +1,5252 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -447079,7 +445879,9 @@ index 000000000..1085d6cde + struct msghdr msg; + struct iovec iov; + struct sockaddr_nl nladdr; ++#ifdef set_fs + mm_segment_t oldfs; ++#endif + char *pg; + int size = 0; + @@ -447117,16 +445919,18 @@ index 000000000..1085d6cde + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = MSG_DONTWAIT; -+ ++#ifdef set_fs + oldfs = get_fs(); + set_fs(KERNEL_DS); ++#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) + err = sock_sendmsg(sock, &msg); +#else + err = sock_sendmsg(sock, &msg, sizeof(req)); +#endif ++#ifdef set_fs + set_fs(oldfs); -+ ++#endif + if (err < 0) + goto out_sock; + @@ -447149,16 +445953,18 @@ index 000000000..1085d6cde +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) + iov_iter_init(&msg.msg_iter, READ, &iov, 1, PAGE_SIZE); +#endif -+ ++#ifdef set_fs + oldfs = get_fs(); + set_fs(KERNEL_DS); ++#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)) + err = sock_recvmsg(sock, &msg, MSG_DONTWAIT); +#else + err = sock_recvmsg(sock, &msg, PAGE_SIZE, MSG_DONTWAIT); +#endif ++#ifdef set_fs + set_fs(oldfs); -+ ++#endif + if (err < 0) + goto out_sock_pg; + @@ -447228,15 +446034,18 @@ index 000000000..1085d6cde + msg.msg_controllen = 0; + msg.msg_flags = MSG_DONTWAIT; + ++#ifdef set_fs + oldfs = get_fs(); + set_fs(KERNEL_DS); ++#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) + err = sock_sendmsg(sock, &msg); +#else + err = sock_sendmsg(sock, &msg, sizeof(req)); +#endif ++#ifdef set_fs + set_fs(oldfs); -+ ++#endif + if (err > 0) + goto restart; + } @@ -448291,11 +447100,9 @@ index 000000000..1085d6cde +EXPORT_SYMBOL(rtw_vendor_ie_set_api); + +#endif -diff --git linux-5.8/3rdparty/rtl8812au/os_dep/linux/recv_linux.c linux-5.8/3rdparty/rtl8812au/os_dep/linux/recv_linux.c -new file mode 100644 -index 000000000..2f7b3e375 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/os_dep/linux/recv_linux.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/recv_linux.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/recv_linux.c +--- linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/recv_linux.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/recv_linux.c 2021-03-07 18:16:17.096958038 +0200 @@ -0,0 +1,739 @@ +/****************************************************************************** + * @@ -449036,11 +447843,9 @@ index 000000000..2f7b3e375 + +} + -diff --git linux-5.8/3rdparty/rtl8812au/os_dep/linux/rhashtable.c linux-5.8/3rdparty/rtl8812au/os_dep/linux/rhashtable.c -new file mode 100644 -index 000000000..af9c9aec8 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/os_dep/linux/rhashtable.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rhashtable.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/rhashtable.c +--- linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rhashtable.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/rhashtable.c 2021-03-07 18:16:17.096958038 +0200 @@ -0,0 +1,844 @@ +/* + * Resizable, Scalable, Concurrent Hash Table @@ -449886,11 +448691,9 @@ index 000000000..af9c9aec8 + return rhashtable_free_and_destroy(ht, NULL, NULL); +} + -diff --git linux-5.8/3rdparty/rtl8812au/os_dep/linux/rhashtable.h linux-5.8/3rdparty/rtl8812au/os_dep/linux/rhashtable.h -new file mode 100644 -index 000000000..a6db3257b ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/os_dep/linux/rhashtable.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rhashtable.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/rhashtable.h +--- linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rhashtable.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/rhashtable.h 2021-03-07 18:16:17.096958038 +0200 @@ -0,0 +1,827 @@ +/* + * Resizable, Scalable, Concurrent Hash Table @@ -450719,11 +449522,9 @@ index 000000000..a6db3257b + +#endif /* _LINUX_RHASHTABLE_H */ + -diff --git linux-5.8/3rdparty/rtl8812au/os_dep/linux/rtw_android.c linux-5.8/3rdparty/rtl8812au/os_dep/linux/rtw_android.c -new file mode 100644 -index 000000000..a373af75d ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/os_dep/linux/rtw_android.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rtw_android.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/rtw_android.c +--- linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rtw_android.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/rtw_android.c 2021-03-07 18:16:17.096958038 +0200 @@ -0,0 +1,1335 @@ +/****************************************************************************** + * @@ -452060,11 +450861,9 @@ index 000000000..a373af75d +#endif /* CONFIG_PLATFORM_INTEL_BYT */ +} +#endif /* CONFIG_GPIO_WAKEUP */ -diff --git linux-5.8/3rdparty/rtl8812au/os_dep/linux/rtw_proc.c linux-5.8/3rdparty/rtl8812au/os_dep/linux/rtw_proc.c -new file mode 100644 -index 000000000..f1016e1cc ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/os_dep/linux/rtw_proc.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rtw_proc.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/rtw_proc.c +--- linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rtw_proc.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/rtw_proc.c 2021-03-07 18:16:17.097958085 +0200 @@ -0,0 +1,4745 @@ +/****************************************************************************** + * @@ -456811,11 +455610,9 @@ index 000000000..f1016e1cc +} + +#endif /* CONFIG_PROC_DEBUG */ -diff --git linux-5.8/3rdparty/rtl8812au/os_dep/linux/rtw_proc.h linux-5.8/3rdparty/rtl8812au/os_dep/linux/rtw_proc.h -new file mode 100644 -index 000000000..c2c7c8ed8 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/os_dep/linux/rtw_proc.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rtw_proc.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/rtw_proc.h +--- linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rtw_proc.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/rtw_proc.h 2021-03-07 18:16:17.097958085 +0200 @@ -0,0 +1,60 @@ +/****************************************************************************** + * @@ -456877,11 +455674,9 @@ index 000000000..c2c7c8ed8 +#endif /* !CONFIG_PROC_DEBUG */ + +#endif /* __RTW_PROC_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/os_dep/linux/rtw_rhashtable.c linux-5.8/3rdparty/rtl8812au/os_dep/linux/rtw_rhashtable.c -new file mode 100644 -index 000000000..4d51f0482 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/os_dep/linux/rtw_rhashtable.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rtw_rhashtable.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/rtw_rhashtable.c +--- linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rtw_rhashtable.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/rtw_rhashtable.c 2021-03-07 18:16:17.097958085 +0200 @@ -0,0 +1,74 @@ +/****************************************************************************** + * @@ -456957,11 +455752,9 @@ index 000000000..4d51f0482 + +#endif /* CONFIG_RTW_MESH */ + -diff --git linux-5.8/3rdparty/rtl8812au/os_dep/linux/rtw_rhashtable.h linux-5.8/3rdparty/rtl8812au/os_dep/linux/rtw_rhashtable.h -new file mode 100644 -index 000000000..567ab3910 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/os_dep/linux/rtw_rhashtable.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rtw_rhashtable.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/rtw_rhashtable.h +--- linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rtw_rhashtable.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/rtw_rhashtable.h 2021-03-07 18:16:17.097958085 +0200 @@ -0,0 +1,55 @@ +/****************************************************************************** + * @@ -457018,11 +455811,9 @@ index 000000000..567ab3910 + +#endif /* __RTW_RHASHTABLE_H__ */ + -diff --git linux-5.8/3rdparty/rtl8812au/os_dep/linux/usb_intf.c linux-5.8/3rdparty/rtl8812au/os_dep/linux/usb_intf.c -new file mode 100644 -index 000000000..8180403b3 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/os_dep/linux/usb_intf.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/usb_intf.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/usb_intf.c +--- linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/usb_intf.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/usb_intf.c 2021-03-07 18:16:17.097958085 +0200 @@ -0,0 +1,1658 @@ +/****************************************************************************** + * @@ -458682,11 +457473,9 @@ index 000000000..8180403b3 +} +EXPORT_SYMBOL(rtw_usb_get_sw_pointer); +#endif /* CONFIG_INTEL_PROXIM */ -diff --git linux-5.8/3rdparty/rtl8812au/os_dep/linux/usb_ops_linux.c linux-5.8/3rdparty/rtl8812au/os_dep/linux/usb_ops_linux.c -new file mode 100644 -index 000000000..16fc944a1 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/os_dep/linux/usb_ops_linux.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/usb_ops_linux.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/usb_ops_linux.c +--- linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/usb_ops_linux.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/usb_ops_linux.c 2021-03-07 18:16:17.097958085 +0200 @@ -0,0 +1,1135 @@ +/****************************************************************************** + * @@ -459823,11 +458612,9 @@ index 000000000..16fc944a1 + return ret; +} +#endif /* CONFIG_USB_INTERRUPT_IN_PIPE */ -diff --git linux-5.8/3rdparty/rtl8812au/os_dep/linux/wifi_regd.c linux-5.8/3rdparty/rtl8812au/os_dep/linux/wifi_regd.c -new file mode 100644 -index 000000000..5f2f90506 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/os_dep/linux/wifi_regd.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/wifi_regd.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/wifi_regd.c +--- linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/wifi_regd.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/wifi_regd.c 2021-03-07 18:16:17.097958085 +0200 @@ -0,0 +1,437 @@ +/****************************************************************************** + * @@ -460266,11 +459053,9 @@ index 000000000..5f2f90506 + return 0; +} +#endif /* CONFIG_IOCTL_CFG80211 */ -diff --git linux-5.8/3rdparty/rtl8812au/os_dep/linux/xmit_linux.c linux-5.8/3rdparty/rtl8812au/os_dep/linux/xmit_linux.c -new file mode 100644 -index 000000000..ebbf1f00e ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/os_dep/linux/xmit_linux.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/xmit_linux.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/xmit_linux.c +--- linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/xmit_linux.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/linux/xmit_linux.c 2021-03-07 18:16:17.097958085 +0200 @@ -0,0 +1,567 @@ +/****************************************************************************** + * @@ -460839,12 +459624,10 @@ index 000000000..ebbf1f00e + + return ret; +} -diff --git linux-5.8/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.8/3rdparty/rtl8812au/os_dep/osdep_service.c -new file mode 100644 -index 000000000..7c6d12088 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/os_dep/osdep_service.c -@@ -0,0 +1,3159 @@ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/osdep_service.c +--- linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/os_dep/osdep_service.c 2021-03-07 18:16:17.098958132 +0200 +@@ -0,0 +1,3172 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -463011,11 +461794,21 @@ index 000000000..7c6d12088 +{ + int wlen = 0, sum = 0; + ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) ++ if (!(fp->f_mode & FMODE_CAN_WRITE)) ++#else + if (!fp->f_op || !fp->f_op->write) ++#endif + return -EPERM; + + while (sum < len) { ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)) ++ wlen = kernel_write(fp, buf + sum, len - sum, &fp->f_pos); ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) ++ wlen = __vfs_write(fp, buf + sum, len - sum, &fp->f_pos); ++#else + wlen = fp->f_op->write(fp, buf + sum, len - sum, &fp->f_pos); ++#endif + if (wlen > 0) + sum += wlen; + else if (0 != wlen) @@ -463038,19 +461831,19 @@ index 000000000..7c6d12088 +{ + struct file *fp; + int ret = 0; ++#ifdef set_fs + mm_segment_t oldfs; ++#endif + char buf; + + fp = filp_open(path, O_RDONLY, 0); + if (IS_ERR(fp)) + ret = PTR_ERR(fp); + else { ++#ifdef set_fs + oldfs = get_fs(); -+ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)) + set_fs(KERNEL_DS); -+ #else -+ set_fs(get_ds()); -+ #endif ++#endif + + if (1 != readFile(fp, &buf, 1)) + ret = PTR_ERR(fp); @@ -463062,8 +461855,9 @@ index 000000000..7c6d12088 + *sz = i_size_read(fp->f_dentry->d_inode); + #endif + } -+ ++#ifdef set_fs + set_fs(oldfs); ++#endif + filp_close(fp, NULL); + } + return ret; @@ -463079,22 +461873,23 @@ index 000000000..7c6d12088 +static int retriveFromFile(const char *path, u8 *buf, u32 sz) +{ + int ret = -1; ++#ifdef set_fs + mm_segment_t oldfs; ++#endif + struct file *fp; + + if (path && buf) { + ret = openFile(&fp, path, O_RDONLY, 0); + if (0 == ret) { + RTW_INFO("%s openFile path:%s fp=%p\n", __FUNCTION__, path , fp); -+ ++#ifdef set_fs + oldfs = get_fs(); -+ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)) + set_fs(KERNEL_DS); -+ #else -+ set_fs(get_ds()); -+ #endif + ret = readFile(fp, buf, sz); + set_fs(oldfs); ++#else ++ ret = readFile(fp, buf, sz); ++#endif + closeFile(fp); + + RTW_INFO("%s readFile, ret:%d\n", __FUNCTION__, ret); @@ -463118,22 +461913,23 @@ index 000000000..7c6d12088 +static int storeToFile(const char *path, u8 *buf, u32 sz) +{ + int ret = 0; ++#ifdef set_fs + mm_segment_t oldfs; ++#endif + struct file *fp; + + if (path && buf) { + ret = openFile(&fp, path, O_CREAT | O_WRONLY, 0666); + if (0 == ret) { + RTW_INFO("%s openFile path:%s fp=%p\n", __FUNCTION__, path , fp); -+ ++#ifdef set_fs + oldfs = get_fs(); -+ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)) + set_fs(KERNEL_DS); -+ #else -+ set_fs(get_ds()); -+ #endif + ret = writeFile(fp, buf, sz); + set_fs(oldfs); ++#else ++ ret = writeFile(fp, buf, sz); ++#endif + closeFile(fp); + + RTW_INFO("%s writeFile, ret:%d\n", __FUNCTION__, ret); @@ -464004,11 +462800,9 @@ index 000000000..7c6d12088 + return 0; +} + -diff --git linux-5.8/3rdparty/rtl8812au/platform/custom_country_chplan.h linux-5.8/3rdparty/rtl8812au/platform/custom_country_chplan.h -new file mode 100644 -index 000000000..f8cc13bf1 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/platform/custom_country_chplan.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/custom_country_chplan.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/custom_country_chplan.h +--- linux-5.11.4/3rdparty/rtl8812au/platform/custom_country_chplan.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/custom_country_chplan.h 2021-03-07 18:16:17.098958132 +0200 @@ -0,0 +1,22 @@ +/****************************************************************************** + * @@ -464032,11 +462826,160 @@ index 000000000..f8cc13bf1 + COUNTRY_CHPLAN_ENT("TW", 0x76, 1, 0x3FF), /* Taiwan */ +}; + -diff --git linux-5.8/3rdparty/rtl8812au/platform/platform_ARM_SUN50IW1P1_sdio.c linux-5.8/3rdparty/rtl8812au/platform/platform_ARM_SUN50IW1P1_sdio.c -new file mode 100644 -index 000000000..2586455de ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/platform/platform_ARM_SUN50IW1P1_sdio.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_aml_s905_sdio.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_aml_s905_sdio.c +--- linux-5.11.4/3rdparty/rtl8812au/platform/platform_aml_s905_sdio.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_aml_s905_sdio.c 2021-03-07 18:16:17.098958132 +0200 +@@ -0,0 +1,54 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2016 - 2018 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++#include /* pr_info(() */ ++#include /* msleep() */ ++#include "platform_aml_s905_sdio.h" /* sdio_reinit() and etc */ ++ ++ ++/* ++ * Return: ++ * 0: power on successfully ++ * others: power on failed ++ */ ++int platform_wifi_power_on(void) ++{ ++ int ret = 0; ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) ++ ret = wifi_setup_dt(); ++ if (ret) { ++ pr_err("%s: setup dt failed!!(%d)\n", __func__, ret); ++ return -1; ++ } ++#endif /* kernel < 3.14.0 */ ++ ++#if 0 /* Seems redundancy? Already done before insert driver */ ++ pr_info("######%s:\n", __func__); ++ extern_wifi_set_enable(0); ++ msleep(500); ++ extern_wifi_set_enable(1); ++ msleep(500); ++ sdio_reinit(); ++#endif ++ ++ return ret; ++} ++ ++void platform_wifi_power_off(void) ++{ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) ++ wifi_teardown_dt(); ++#endif /* kernel < 3.14.0 */ ++} +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_aml_s905_sdio.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_aml_s905_sdio.h +--- linux-5.11.4/3rdparty/rtl8812au/platform/platform_aml_s905_sdio.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_aml_s905_sdio.h 2021-03-07 18:16:17.098958132 +0200 +@@ -0,0 +1,32 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2016 - 2018 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++#ifndef __PLATFORM_AML_S905_SDIO_H__ ++#define __PLATFORM_AML_S905_SDIO_H__ ++ ++#include /* Linux vresion */ ++#ifndef RHEL_RELEASE_CODE ++#define RHEL_RELEASE_VERSION(a,b) (((a) << 8) + (b)) ++#define RHEL_RELEASE_CODE 0 ++#endif ++ ++extern void sdio_reinit(void); ++extern void extern_wifi_set_enable(int is_on); ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) ++extern void wifi_teardown_dt(void); ++extern int wifi_setup_dt(void); ++#endif /* kernel < 3.14.0 */ ++ ++#endif /* __PLATFORM_AML_S905_SDIO_H__ */ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_arm_act_sdio.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_arm_act_sdio.c +--- linux-5.11.4/3rdparty/rtl8812au/platform/platform_arm_act_sdio.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_arm_act_sdio.c 2021-03-07 18:16:17.098958132 +0200 +@@ -0,0 +1,53 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2013 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++/* ++ * Description: ++ * This file can be applied to following platforms: ++ * CONFIG_PLATFORM_ACTIONS_ATM703X ++ */ ++#include ++ ++#ifdef CONFIG_PLATFORM_ACTIONS_ATM705X ++extern int acts_wifi_init(void); ++extern void acts_wifi_cleanup(void); ++#endif ++ ++/* ++ * Return: ++ * 0: power on successfully ++ * others: power on failed ++ */ ++int platform_wifi_power_on(void) ++{ ++ int ret = 0; ++ ++#ifdef CONFIG_PLATFORM_ACTIONS_ATM705X ++ ret = acts_wifi_init(); ++ if (unlikely(ret < 0)) { ++ pr_err("%s Failed to register the power control driver.\n", __FUNCTION__); ++ goto exit; ++ } ++#endif ++ ++exit: ++ return ret; ++} ++ ++void platform_wifi_power_off(void) ++{ ++#ifdef CONFIG_PLATFORM_ACTIONS_ATM705X ++ acts_wifi_cleanup(); ++#endif ++} +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_ARM_SUN50IW1P1_sdio.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_ARM_SUN50IW1P1_sdio.c +--- linux-5.11.4/3rdparty/rtl8812au/platform/platform_ARM_SUN50IW1P1_sdio.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_ARM_SUN50IW1P1_sdio.c 2021-03-07 18:16:17.098958132 +0200 @@ -0,0 +1,86 @@ +/****************************************************************************** + * @@ -464124,11 +463067,9 @@ index 000000000..2586455de + RTW_INFO("%s: remove card, power off.\n", __FUNCTION__); +#endif /* CONFIG_MMC */ +} -diff --git linux-5.8/3rdparty/rtl8812au/platform/platform_ARM_SUNnI_sdio.c linux-5.8/3rdparty/rtl8812au/platform/platform_ARM_SUNnI_sdio.c -new file mode 100644 -index 000000000..8a52aa90c ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/platform/platform_ARM_SUNnI_sdio.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_ARM_SUNnI_sdio.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_ARM_SUNnI_sdio.c +--- linux-5.11.4/3rdparty/rtl8812au/platform/platform_ARM_SUNnI_sdio.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_ARM_SUNnI_sdio.c 2021-03-07 18:16:17.098958132 +0200 @@ -0,0 +1,130 @@ +/****************************************************************************** + * @@ -464260,11 +463201,9 @@ index 000000000..8a52aa90c + RTW_INFO("%s: remove card, power off.\n", __FUNCTION__); +#endif /* CONFIG_MMC */ +} -diff --git linux-5.8/3rdparty/rtl8812au/platform/platform_ARM_SUNxI_sdio.c linux-5.8/3rdparty/rtl8812au/platform/platform_ARM_SUNxI_sdio.c -new file mode 100644 -index 000000000..795b7e7f7 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/platform/platform_ARM_SUNxI_sdio.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_ARM_SUNxI_sdio.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_ARM_SUNxI_sdio.c +--- linux-5.11.4/3rdparty/rtl8812au/platform/platform_ARM_SUNxI_sdio.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_ARM_SUNxI_sdio.c 2021-03-07 18:16:17.098958132 +0200 @@ -0,0 +1,90 @@ +/****************************************************************************** + * @@ -464356,11 +463295,9 @@ index 000000000..795b7e7f7 +#endif /* CONFIG_RTL8188E */ +#endif /* CONFIG_MMC_SUNXI_POWER_CONTROL */ +} -diff --git linux-5.8/3rdparty/rtl8812au/platform/platform_ARM_SUNxI_usb.c linux-5.8/3rdparty/rtl8812au/platform/platform_ARM_SUNxI_usb.c -new file mode 100644 -index 000000000..9c2abc4f6 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/platform/platform_ARM_SUNxI_usb.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_ARM_SUNxI_usb.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_ARM_SUNxI_usb.c +--- linux-5.11.4/3rdparty/rtl8812au/platform/platform_ARM_SUNxI_usb.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_ARM_SUNxI_usb.c 2021-03-07 18:16:17.098958132 +0200 @@ -0,0 +1,136 @@ +/****************************************************************************** + * @@ -464498,11 +463435,9 @@ index 000000000..9c2abc4f6 +#endif /* defined(CONFIG_PLATFORM_ARM_SUN8I) */ + +} -diff --git linux-5.8/3rdparty/rtl8812au/platform/platform_ARM_WMT_sdio.c linux-5.8/3rdparty/rtl8812au/platform/platform_ARM_WMT_sdio.c -new file mode 100644 -index 000000000..d85002c15 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/platform/platform_ARM_WMT_sdio.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_ARM_WMT_sdio.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_ARM_WMT_sdio.c +--- linux-5.11.4/3rdparty/rtl8812au/platform/platform_ARM_WMT_sdio.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_ARM_WMT_sdio.c 2021-03-07 18:16:17.098958132 +0200 @@ -0,0 +1,46 @@ +/****************************************************************************** + * @@ -464550,204 +463485,9 @@ index 000000000..d85002c15 + gpio_free(WMT_PIN_GP62_SUSGPIO1); + printk("[rtl8189es] %s: remove card, power off.\n", __FUNCTION__); +} -diff --git linux-5.8/3rdparty/rtl8812au/platform/platform_RTK_DMP_usb.c linux-5.8/3rdparty/rtl8812au/platform/platform_RTK_DMP_usb.c -new file mode 100644 -index 000000000..cb740b2ee ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/platform/platform_RTK_DMP_usb.c -@@ -0,0 +1,30 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2013 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+#include -+ -+int platform_wifi_power_on(void) -+{ -+ int ret = 0; -+ u32 tmp; -+ tmp = readl((volatile unsigned int *)0xb801a608); -+ tmp &= 0xffffff00; -+ tmp |= 0x55; -+ writel(tmp, (volatile unsigned int *)0xb801a608); /* write dummy register for 1055 */ -+ return ret; -+} -+ -+void platform_wifi_power_off(void) -+{ -+} -diff --git linux-5.8/3rdparty/rtl8812au/platform/platform_aml_s905_sdio.c linux-5.8/3rdparty/rtl8812au/platform/platform_aml_s905_sdio.c -new file mode 100644 -index 000000000..334ca03c9 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/platform/platform_aml_s905_sdio.c -@@ -0,0 +1,54 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2016 - 2018 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+#include /* pr_info(() */ -+#include /* msleep() */ -+#include "platform_aml_s905_sdio.h" /* sdio_reinit() and etc */ -+ -+ -+/* -+ * Return: -+ * 0: power on successfully -+ * others: power on failed -+ */ -+int platform_wifi_power_on(void) -+{ -+ int ret = 0; -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) -+ ret = wifi_setup_dt(); -+ if (ret) { -+ pr_err("%s: setup dt failed!!(%d)\n", __func__, ret); -+ return -1; -+ } -+#endif /* kernel < 3.14.0 */ -+ -+#if 0 /* Seems redundancy? Already done before insert driver */ -+ pr_info("######%s:\n", __func__); -+ extern_wifi_set_enable(0); -+ msleep(500); -+ extern_wifi_set_enable(1); -+ msleep(500); -+ sdio_reinit(); -+#endif -+ -+ return ret; -+} -+ -+void platform_wifi_power_off(void) -+{ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) -+ wifi_teardown_dt(); -+#endif /* kernel < 3.14.0 */ -+} -diff --git linux-5.8/3rdparty/rtl8812au/platform/platform_aml_s905_sdio.h linux-5.8/3rdparty/rtl8812au/platform/platform_aml_s905_sdio.h -new file mode 100644 -index 000000000..17d3cd73c ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/platform/platform_aml_s905_sdio.h -@@ -0,0 +1,32 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2016 - 2018 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+#ifndef __PLATFORM_AML_S905_SDIO_H__ -+#define __PLATFORM_AML_S905_SDIO_H__ -+ -+#include /* Linux vresion */ -+#ifndef RHEL_RELEASE_CODE -+#define RHEL_RELEASE_VERSION(a,b) (((a) << 8) + (b)) -+#define RHEL_RELEASE_CODE 0 -+#endif -+ -+extern void sdio_reinit(void); -+extern void extern_wifi_set_enable(int is_on); -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) -+extern void wifi_teardown_dt(void); -+extern int wifi_setup_dt(void); -+#endif /* kernel < 3.14.0 */ -+ -+#endif /* __PLATFORM_AML_S905_SDIO_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/platform/platform_arm_act_sdio.c linux-5.8/3rdparty/rtl8812au/platform/platform_arm_act_sdio.c -new file mode 100644 -index 000000000..ad7b6cfed ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/platform/platform_arm_act_sdio.c -@@ -0,0 +1,53 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2013 - 2017 Realtek Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ *****************************************************************************/ -+/* -+ * Description: -+ * This file can be applied to following platforms: -+ * CONFIG_PLATFORM_ACTIONS_ATM703X -+ */ -+#include -+ -+#ifdef CONFIG_PLATFORM_ACTIONS_ATM705X -+extern int acts_wifi_init(void); -+extern void acts_wifi_cleanup(void); -+#endif -+ -+/* -+ * Return: -+ * 0: power on successfully -+ * others: power on failed -+ */ -+int platform_wifi_power_on(void) -+{ -+ int ret = 0; -+ -+#ifdef CONFIG_PLATFORM_ACTIONS_ATM705X -+ ret = acts_wifi_init(); -+ if (unlikely(ret < 0)) { -+ pr_err("%s Failed to register the power control driver.\n", __FUNCTION__); -+ goto exit; -+ } -+#endif -+ -+exit: -+ return ret; -+} -+ -+void platform_wifi_power_off(void) -+{ -+#ifdef CONFIG_PLATFORM_ACTIONS_ATM705X -+ acts_wifi_cleanup(); -+#endif -+} -diff --git linux-5.8/3rdparty/rtl8812au/platform/platform_hisilicon_hi3798_sdio.c linux-5.8/3rdparty/rtl8812au/platform/platform_hisilicon_hi3798_sdio.c -new file mode 100644 -index 000000000..11a08320e ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/platform/platform_hisilicon_hi3798_sdio.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_hisilicon_hi3798_sdio.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_hisilicon_hi3798_sdio.c +--- linux-5.11.4/3rdparty/rtl8812au/platform/platform_hisilicon_hi3798_sdio.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_hisilicon_hi3798_sdio.c 2021-03-07 18:16:17.098958132 +0200 @@ -0,0 +1,110 @@ +/****************************************************************************** + * @@ -464859,11 +463599,9 @@ index 000000000..11a08320e + mdelay(100); + hi_gpio_set_value(gpio_wlan_reg_on, 0); +} -diff --git linux-5.8/3rdparty/rtl8812au/platform/platform_hisilicon_hi3798_sdio.h linux-5.8/3rdparty/rtl8812au/platform/platform_hisilicon_hi3798_sdio.h -new file mode 100644 -index 000000000..1ad42406f ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/platform/platform_hisilicon_hi3798_sdio.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_hisilicon_hi3798_sdio.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_hisilicon_hi3798_sdio.h +--- linux-5.11.4/3rdparty/rtl8812au/platform/platform_hisilicon_hi3798_sdio.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_hisilicon_hi3798_sdio.h 2021-03-07 18:16:17.098958132 +0200 @@ -0,0 +1,28 @@ +/****************************************************************************** + * @@ -464893,11 +463631,9 @@ index 000000000..1ad42406f +extern HI_S32 HI_DRV_GPIO_WriteBit(HI_U32 u32GpioNo, HI_U32 u32BitValue); + +#endif /* __PLATFORM_HISILICON_HI3798_SDIO_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/platform/platform_ops.c linux-5.8/3rdparty/rtl8812au/platform/platform_ops.c -new file mode 100644 -index 000000000..10766aad8 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/platform/platform_ops.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_ops.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_ops.c +--- linux-5.11.4/3rdparty/rtl8812au/platform/platform_ops.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_ops.c 2021-03-07 18:16:17.098958132 +0200 @@ -0,0 +1,32 @@ +/****************************************************************************** + * @@ -464931,11 +463667,9 @@ index 000000000..10766aad8 +{ +} +#endif /* !CONFIG_PLATFORM_OPS */ -diff --git linux-5.8/3rdparty/rtl8812au/platform/platform_ops.h linux-5.8/3rdparty/rtl8812au/platform/platform_ops.h -new file mode 100644 -index 000000000..12caf3c85 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/platform/platform_ops.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_ops.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_ops.h +--- linux-5.11.4/3rdparty/rtl8812au/platform/platform_ops.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_ops.h 2021-03-07 18:16:17.098958132 +0200 @@ -0,0 +1,26 @@ +/****************************************************************************** + * @@ -464963,11 +463697,43 @@ index 000000000..12caf3c85 +void platform_wifi_power_off(void); + +#endif /* __PLATFORM_OPS_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/platform/platform_sprd_sdio.c linux-5.8/3rdparty/rtl8812au/platform/platform_sprd_sdio.c -new file mode 100644 -index 000000000..34061d05d ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/platform/platform_sprd_sdio.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_RTK_DMP_usb.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_RTK_DMP_usb.c +--- linux-5.11.4/3rdparty/rtl8812au/platform/platform_RTK_DMP_usb.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_RTK_DMP_usb.c 2021-03-07 18:16:17.098958132 +0200 +@@ -0,0 +1,30 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2013 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ *****************************************************************************/ ++#include ++ ++int platform_wifi_power_on(void) ++{ ++ int ret = 0; ++ u32 tmp; ++ tmp = readl((volatile unsigned int *)0xb801a608); ++ tmp &= 0xffffff00; ++ tmp |= 0x55; ++ writel(tmp, (volatile unsigned int *)0xb801a608); /* write dummy register for 1055 */ ++ return ret; ++} ++ ++void platform_wifi_power_off(void) ++{ ++} +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_sprd_sdio.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_sprd_sdio.c +--- linux-5.11.4/3rdparty/rtl8812au/platform/platform_sprd_sdio.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_sprd_sdio.c 2021-03-07 18:16:17.098958132 +0200 @@ -0,0 +1,84 @@ +/****************************************************************************** + * @@ -465053,11 +463819,9 @@ index 000000000..34061d05d + mmc_host->pm_flags &= ~MMC_PM_KEEP_POWER; +#endif /* CONFIG_WOWLAN */ +} -diff --git linux-5.8/3rdparty/rtl8812au/platform/platform_zte_zx296716_sdio.c linux-5.8/3rdparty/rtl8812au/platform/platform_zte_zx296716_sdio.c -new file mode 100644 -index 000000000..472d24d85 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/platform/platform_zte_zx296716_sdio.c +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_zte_zx296716_sdio.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_zte_zx296716_sdio.c +--- linux-5.11.4/3rdparty/rtl8812au/platform/platform_zte_zx296716_sdio.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_zte_zx296716_sdio.c 2021-03-07 18:16:17.098958132 +0200 @@ -0,0 +1,53 @@ +/****************************************************************************** + * @@ -465112,11 +463876,9 @@ index 000000000..472d24d85 + + /*msleep(500);*/ +} -diff --git linux-5.8/3rdparty/rtl8812au/platform/platform_zte_zx296716_sdio.h linux-5.8/3rdparty/rtl8812au/platform/platform_zte_zx296716_sdio.h -new file mode 100644 -index 000000000..3a4fba1a5 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/platform/platform_zte_zx296716_sdio.h +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_zte_zx296716_sdio.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_zte_zx296716_sdio.h +--- linux-5.11.4/3rdparty/rtl8812au/platform/platform_zte_zx296716_sdio.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/platform/platform_zte_zx296716_sdio.h 2021-03-07 18:16:17.098958132 +0200 @@ -0,0 +1,25 @@ +/****************************************************************************** + * @@ -465143,2266 +463905,11 @@ index 000000000..3a4fba1a5 +#endif /* CONFIG_A16T03_BOARD */ + +#endif /* __PLATFORM_ZTE_ZX296716_SDIO_H__ */ -diff --git linux-5.8/3rdparty/rtl8812au/tools/RtkMpTool-ReadMe.txt linux-5.8/3rdparty/rtl8812au/tools/RtkMpTool-ReadMe.txt -new file mode 100644 -index 000000000..82516dcd4 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/tools/RtkMpTool-ReadMe.txt -@@ -0,0 +1,18 @@ -+RtkMpTool.apk need to use "rtwpriv", -+please frist to prepare build the rtwpriv and push to Android system. -+ -+Installation steps: -+1. adb push rtwpriv /system/bin/ -+2. adb shell chmod 755 /system/bin/rtwpriv -+3. adb push 8xxx.ko "your system wlan default module's folder"\wlan.ko (etc. /system/lib/modules/wlan.ko) -+4. adb install RtkMpTool.apk -+or adb install RtkWiFiTest.apk -+5. a.After execute the MP tool.Frist to use the "adb shell rtwpriv wlan0 mp_start" to check this driver can support mp command. -+ b.The "mp_start" command must to be no show any error message. -+ -+P.S. -+1. RtkMpTool.apk only supports the MP test functions. -+After installed, you will see a "Realtek MP Tool" App on the phone. -+ -+2. RtkWiFiTest.apk supports both MP test and CTA test functions. -+After installed, you will see a "WiFi Test" App on the phone. -diff --git linux-5.8/3rdparty/rtl8812au/tools/RtkMpTool.apk linux-5.8/3rdparty/rtl8812au/tools/RtkMpTool.apk -new file mode 100644 -index 000000000..c99b47a83 -Binary files /dev/null and linux-5.8/3rdparty/rtl8812au/tools/RtkMpTool.apk differ -diff --git linux-5.8/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/Android.mk linux-5.8/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/Android.mk -new file mode 100644 -index 000000000..7823c1402 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/Android.mk -@@ -0,0 +1,11 @@ -+ifneq ($(TARGET_SIMULATOR),true) -+LOCAL_PATH:= $(call my-dir) -+ -+include $(CLEAR_VARS) -+LOCAL_SRC_FILES += p2p_api_test_linux.c p2p_ui_test_linux.c -+LOCAL_SHARED_LIBRARIES := libc libcutils -+LOCAL_MODULE = P2P_UI -+LOCAL_MODULE_TAGS := optional -+include $(BUILD_EXECUTABLE) -+ -+endif -diff --git linux-5.8/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/Start_Guide_P2P_User_Interface_Linux.pdf linux-5.8/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/Start_Guide_P2P_User_Interface_Linux.pdf -new file mode 100644 -index 000000000..299064fa2 -Binary files /dev/null and linux-5.8/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/Start_Guide_P2P_User_Interface_Linux.pdf differ -diff --git linux-5.8/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/install.sh linux-5.8/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/install.sh -new file mode 100755 -index 000000000..519b8fc69 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/install.sh -@@ -0,0 +1,100 @@ -+ -+wpa_supplicant_hostapd=`ls -1 ../wpa_supplicant_hostapd/wpa_supplicant_hostapd-0.8_*` -+echo $wpa_supplicant_hostapd -+ -+ -+if [ -e $wpa_supplicant_hostapd ]; then -+ echo "Checking wpa_supplicant_hostatpd" -+else -+ echo "wpa_supplicant_hostapd doesn'tt exist in corresponding folder" -+ exit -+fi -+ -+if [ -e ../wpa_supplicant_hostapd/p2p_hostapd.conf ]; then -+ echo "Checking p2p_hostapd.conf" -+else -+ echo "p2p_hostapd.conf doesn't exist in corresponding folder" -+ exit -+fi -+ -+if [ -e ../wpa_supplicant_hostapd/wpa_0_8.conf ]; then -+ echo "Checking wpa_0_8.conf" -+else -+ echo "wpa_0_8.conf doesn't exist in corresponding folder" -+ exit -+fi -+ -+#cp ../wpa_supplicant_hostapd/wpa_supplicant_hostapd-0.8_rtw_20111118.zip ./ -+cp $wpa_supplicant_hostapd ./ -+wpa_supplicant_hostapd=`ls -1 ./wpa_supplicant_hostapd-0.8_*` -+echo " "$wpa_supplicant_hostapd -+unzip $wpa_supplicant_hostapd -+ -+cd wpa_supplicant_hostapd-0.8 -+cd wpa_supplicant -+make clean all -+ -+cd .. -+cd hostapd -+make clean all -+ -+cd .. -+cd .. -+ -+cp ../wpa_supplicant_hostapd/p2p_hostapd.conf ./ -+cp ../wpa_supplicant_hostapd/wpa_0_8.conf ./ -+cp ./wpa_supplicant_hostapd-0.8/hostapd/hostapd ./ -+cp ./wpa_supplicant_hostapd-0.8/hostapd/hostapd_cli ./ -+cp ./wpa_supplicant_hostapd-0.8/wpa_supplicant/wpa_supplicant ./ -+cp ./wpa_supplicant_hostapd-0.8/wpa_supplicant/wpa_cli ./ -+ -+rm -rf wpa_supplicant_hostapd-0.8 -+rm -rf $wpa_supplicant_hostapd -+ -+gcc -o P2P_UI ./p2p_api_test_linux.c ./p2p_ui_test_linux.c -lpthread -+ -+if [ ! -e ./p2p_hostapd.conf ]; then -+ echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" -+ echo "Doesn't have p2p_hostapd.conf" -+ result="fail" -+fi -+ -+if [ ! -e ./wpa_0_8.conf ]; then -+ echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" -+ echo "Doesn't have wpa_0_8.conf" -+ result="fail" -+fi -+ -+if [ ! -e ./hostapd ]; then -+ echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" -+ echo "Doesn't have hostapd" -+ result="fail" -+fi -+ -+if [ ! -e ./wpa_supplicant ]; then -+ echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" -+ echo "Doesn't have hostapd_cli" -+ result="fail" -+fi -+ -+if [ ! -e ./wpa_cli ]; then -+ echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" -+ echo "Doesn't have p2p_hostapd.conf" -+ result="fail" -+fi -+ -+if [ ! -e ./P2P_UI ]; then -+ echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" -+ echo "Doesn't have P2P_UI" -+ result="fail" -+fi -+ -+if [ "$result" == "fail" ]; then -+ echo "WiFi_Direct_User_Interface install unsuccessful" -+ echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" -+ exit -+fi -+ -+echo "##################################################" -+echo "WiFi_Direct_User_Interface install complete!!!!!!!" -+echo "##################################################" -diff --git linux-5.8/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/p2p_api_test_linux.c linux-5.8/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/p2p_api_test_linux.c -new file mode 100644 -index 000000000..4c49b6463 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/p2p_api_test_linux.c -@@ -0,0 +1,1377 @@ -+ -+#include "p2p_test.h" -+ -+unsigned int wps_pin_checksum(unsigned int pin) -+{ -+ unsigned int accum = 0; -+ while( pin ) -+ { -+ accum += pin % 10; -+ pin /= 10; -+ accum += 3 * (pin % 10); -+ pin /= 10; -+ } -+ return( accum % 10 ); -+} -+ -+char lower(char s) -+{ -+ if(('A' <= s) && (s <= 'Z')) -+ return ( s = 'a' + (s - 'A') ); -+ return s; -+} -+ -+int p2p_check_success(struct p2p *p) -+{ -+ int ret = 0; -+ -+ if( p->status == P2P_STATE_GONEGO_OK ) -+ ret = 1; -+ -+ return ret; -+} -+ -+int read_all_sta(struct p2p *p) -+{ -+ int sta_count = 0; -+ FILE *pf; -+ -+ memset( p->cmd, 0x00, CMD_SZ ); -+ sprintf( p->cmd, "%s all_sta > supp_status.txt", p->apcli_path); -+ system( p->cmd ); -+ pf = fopen( "./supp_status.txt", "r" ); -+ if ( pf ) -+ { -+ while( !feof( pf ) ){ -+ memset( p->parse, 0x00, CMD_SZ ); -+ fgets( p->parse, CMD_SZ, pf ); -+ if( strncmp( p->parse, "dot11RSNAStatsSTAAddress=", 25) == 0 ) -+ { -+ sta_count++; -+ if( p->no_sta_connected == sta_count ) -+ return _TRUE; -+ } -+ } -+ -+ fclose( pf ); -+ } -+ -+ return _FALSE; -+} -+ -+void do_wps(struct p2p *p) -+{ -+ FILE *pf = NULL; -+ int ret = _FALSE, parsing_ok = _FALSE; -+ -+ do -+ { -+ memset( p->cmd, 0x00, CMD_SZ ); -+ if( p->ap_open == _TRUE ) -+ { -+ if(p->wps_info==1 || p->wps_info==2) -+ sprintf( p->cmd, "%s wps_pin any %d > supp_status.txt", p->apcli_path, p->pin); -+ else if(p->wps_info==3) -+ sprintf( p->cmd, "%s wps_pbc any > supp_status.txt", p->apcli_path); -+ } -+ else if(p->wpa_open == _TRUE) -+ { -+ if(p->connect_go==1) -+ { -+ if(p->wps_info==1 || p->wps_info==2) -+ sprintf( p->cmd, "%s wps_pin %s %d > supp_status.txt ", p->wpacli_path, p->peer_devaddr, p->pin); -+ else if(p->wps_info==3) -+ sprintf( p->cmd, "%s wps_pbc %s > supp_status.txt ", p->wpacli_path, p->peer_devaddr); -+ } -+ else if( strncmp(p->peer_ifaddr, "00:00:00:00:00:00", 17)==0 ) -+ { -+ if(p->wps_info==1 || p->wps_info==2) -+ sprintf( p->cmd, "%s wps_pin any %d > supp_status.txt ", p->wpacli_path, p->pin); -+ else if(p->wps_info==3) -+ sprintf( p->cmd, "%s wps_pbc any > supp_status.txt ", p->wpacli_path); -+ } -+ else -+ { -+ if(p->wps_info==1 || p->wps_info==2) -+ sprintf( p->cmd, "%s wps_pin %s %d > supp_status.txt ", p->wpacli_path, p->peer_ifaddr, p->pin); -+ else if(p->wps_info==3) -+ sprintf( p->cmd, "%s wps_pbc %s > supp_status.txt ", p->wpacli_path, p->peer_ifaddr); -+ } -+ } -+ system( p->cmd ); -+ -+ pf = fopen( "./supp_status.txt", "r" ); -+ if ( pf ) -+ { -+ while( !feof( pf ) ){ -+ memset(p->parse, 0x00, CMD_SZ); -+ fgets(p->parse, CMD_SZ, pf); -+ -+ if(p->ap_open == _TRUE) -+ { -+ if( (p->wps_info==1 || p->wps_info==2) && (strncmp(p->parse, "", 2) == 0) ) -+ parsing_ok = _TRUE; -+ else if( (p->wps_info==3) && (strncmp(p->parse, "OK", 2) == 0) ) -+ parsing_ok = _TRUE; -+ } -+ else if(p->wpa_open == _TRUE) -+ { -+ if( (p->wps_info==1 || p->wps_info==2) && (strncmp(p->parse, "Selected", 8) == 0) ) -+ parsing_ok = _TRUE; -+ else if( (p->wps_info==3) && (strncmp(p->parse, "OK", 2) == 0) ) -+ parsing_ok = _TRUE; -+ } -+ -+ if( parsing_ok == _TRUE ) -+ { -+ ret = _TRUE; -+ p->wpsing = _TRUE; -+ } -+ } -+ -+ fclose( pf ); -+ } -+ -+ if( ret == 0 ) -+ usleep( HOSTAPD_INIT_TIME ); -+ } -+ while( ret == 0 ); -+} -+ -+void p2p_enable(struct p2p *p) -+{ -+ p->have_p2p_dev = 0; -+ p->connect_go = 0; -+ -+ if(p->enable == -1 ) -+ { -+ if(p->wpa_open == _TRUE){ -+ p->wpa_open = _FALSE; -+ system("killall wpa_supplicant"); -+#ifdef DHCP -+ system("killall dhclient"); -+#endif -+ } -+ if(p->ap_open == _TRUE){ -+ p->ap_open = _FALSE; -+ system("killall hostapd"); -+#ifdef DHCP -+ system("killall dhcpd"); -+#endif -+ } -+ -+ memset( p->cmd, 0x00, CMD_SZ ); -+ sprintf( p->cmd, "iwpriv %s p2p_set enable=0", p->ifname); -+ system( p->cmd ); -+ -+ return; -+ } -+ -+ p->p2p_get=0; -+ memset( p->cmd, 0x00, CMD_SZ ); -+ sprintf( p->cmd, "iwpriv %s p2p_set enable=%d", p->ifname, p->enable); -+ system( p->cmd ); -+ -+ if( p->enable == P2P_ROLE_DISABLE ) -+ { -+ p->wps_info = 0; -+ p->pin = 12345670; -+ -+ p2p_status(p, 0); -+ p2p_role(p, 0); -+ -+ if(p->res == 0) -+ { -+ p->res = 1; -+ } -+ -+ if(p->res_go == 0) -+ { -+ p->res_go = 1; -+ } -+ -+ p->wpa_open = _FALSE; -+ system("killall wpa_supplicant"); -+#ifdef DHCP -+ system("killall dhclient"); -+#endif -+ system("clear"); -+ p->ap_open = _FALSE; -+ system("killall hostapd"); -+#ifdef DHCP -+ system("killall dhcpd"); -+#endif -+ system("clear"); -+ -+ } -+ else if( p->enable == P2P_ROLE_DEVICE ) -+ { -+ char msg[5] = "NULL"; -+ -+#ifdef P2P_AUTO -+ p->res = pthread_create(&p->pthread, NULL, &polling_status, (void *)p); -+#endif -+ -+ if( p->res !=0 ) -+ { -+ p->p2p_get=1; -+ memset( p->print_line, 0x00, CMD_SZ ); -+ sprintf( p->print_line, "Thread creation failed" ); -+ } -+ -+ if(p->wpa_open == _TRUE){ -+ p->wpa_open = _FALSE; -+ system("killall wpa_supplicant"); -+#ifdef DHCP -+ system("killall dhclient"); -+#endif -+ } -+ if(p->ap_open == _TRUE){ -+ p->ap_open = _FALSE; -+ system("killall hostapd"); -+#ifdef DHCP -+ system("killall dhcpd"); -+#endif -+ } -+ -+ p->intent = 1; -+ p2p_intent(p); -+ -+ p2p_set_opch(p, NULL, 0); -+ usleep(50000); -+ p2p_softap_ssid(p, NULL, 0); -+ -+ p2p_setDN(p); -+ p2p_role(p, 0); -+ -+ p2p_scan(p); -+ -+ } -+ else if( p->enable == P2P_ROLE_CLIENT ) -+ { -+ if(p->ap_open == _TRUE){ -+ p->ap_open = _FALSE; -+ system("killall hostapd"); -+#ifdef DHCP -+ system("killall dhcpd"); -+#endif -+ } -+ -+ p2p_status(p, 0); -+ p2p_role(p, 0); -+ p2p_intent(p); -+ } -+ else if( p->enable == P2P_ROLE_GO ) -+ { -+ if(p->wpa_open == _TRUE){ -+ p->wpa_open = _FALSE; -+ system("killall wpa_supplicant"); -+#ifdef DHCP -+ system("killall dhclient"); -+#endif -+ } -+ -+ p2p_status(p, 0); -+ p2p_role(p, 0); -+ p2p_intent(p); -+ -+ p2p_set_opch(p, NULL, 0); -+ usleep(50000); -+ p2p_softap_ssid(p, NULL, 0); -+ -+ p2p_setDN(p); -+ -+ if(p->ap_open != _TRUE) -+ { -+ memset( p->cmd, 0x00, CMD_SZ ); -+ sprintf( p->cmd, "%s -B %s > temp.txt",p->ap_path, p->ap_conf); -+ system( p->cmd ); -+ -+ p->ap_open = _TRUE; -+ } -+ -+#ifdef P2P_AUTO -+ p->res_go = pthread_create(&p->pthread_go, NULL, &polling_client, (void *)p); -+#endif -+ -+ if( p->res_go != 0 ) -+ { -+ p->p2p_get=1; -+ memset( p->print_line, 0x00, CMD_SZ ); -+ sprintf( p->print_line, "Thread creation failed" ); -+ } -+ -+ } -+ -+} -+ -+void p2p_scan(struct p2p *p) -+{ -+ p->p2p_get=0; -+ if( p->enable >= P2P_ROLE_DEVICE ) -+ { -+ p->have_p2p_dev=1; -+ memset( p->cmd, 0x00, CMD_SZ ); -+ sprintf( p->cmd, "iwlist %s scan > scan.txt", p->ifname ); -+ system( p->cmd ); -+ -+ p2p_status(p, 0); -+ -+ } -+ else -+ { -+ p->p2p_get=1; -+ memset( p->print_line, 0x00, CMD_SZ ); -+ sprintf( p->print_line, "%s", p->scan_msg ); -+ } -+} -+ -+void scan_result(struct p2p *p) -+{ -+ FILE *pf=NULL; -+ int no_dev=0; -+ char cms[30] = { 0x00 }; -+ char dns[SSID_SZ] = { 0x00 }; -+ char parse[100] = { 0x00 }; -+ struct scan *pscan_pool; -+ -+ pf = fopen( "./scan.txt", "r" ); -+ if ( pf ) -+ { -+ p->count_line=0; -+ while( (!feof( pf )) && (no_dev < SCAN_POOL_NO)) -+ { -+ memset( parse, 0x00, CMD_SZ ); -+ fgets( parse, CMD_SZ, pf ); -+ -+ if(parse[0] == '\n' || parse[0] == '\0') -+ break; -+ if( strncmp(parse+10, "Scan completed :", 16) == 0 ) -+ { -+ printf("* NO DEVICE NAME BSSID GO CONFIG METHOD *\n"); -+ p->count_line++; -+ } -+ else if( strncmp(parse+20, "Address:", 8) == 0 ) -+ { -+ pscan_pool = &p->scan_pool[no_dev]; -+ memset( pscan_pool->addr, 0x00, sizeof(struct scan) ); -+ strncpy( pscan_pool->addr, parse+29, 17); -+ } -+ else if( strncmp(parse+20, "ESSID:", 6) == 0 ) -+ { -+ pscan_pool = &p->scan_pool[no_dev]; -+ -+ p2p_wps_cm(p, pscan_pool->addr, cms); -+ p2p_device_name(p, pscan_pool->addr, dns); -+ -+ if( strncmp(parse+26, "\"DIRECT-\"", 9) == 0 ) -+ { -+ printf("*[%02d] %-25s %s %-38s*\n",no_dev+1, dns, pscan_pool->addr, cms); -+ } -+ else -+ { -+ printf("*[%02d] %-25s %s * %-38s*\n",no_dev+1, dns, pscan_pool->addr, cms); -+ pscan_pool->go = 1; -+ } -+ p->count_line++; -+ no_dev++; -+ -+ } -+ } -+ -+ if( p->count_line < (SCAN_POOL_NO + 1) ) -+ { -+ for(p->count_line; p->count_line < SCAN_POOL_NO+1; p->count_line++ ) -+ printf("* *\n"); -+ } -+ fclose( pf ); -+ } -+ -+} -+ -+void p2p_setDN(struct p2p *p) -+{ -+ -+ memset( p->cmd, 0x00, CMD_SZ ); -+ sprintf( p->cmd, "iwpriv %s p2p_set setDN=%s", p->ifname, p->dev_name); -+ system( p->cmd ); -+} -+ -+void p2p_intent(struct p2p *p) -+{ -+ p->p2p_get=0; -+ memset( p->cmd, 0x00, CMD_SZ ); -+ sprintf( p->cmd, "iwpriv %s p2p_set intent=%d", p->ifname, p->intent); -+ system( p->cmd ); -+} -+ -+void p2p_wpsinfo(struct p2p *p) -+{ -+ p->p2p_get=0; -+ memset( p->cmd, 0x00, CMD_SZ ); -+ sprintf( p->cmd, "iwpriv %s p2p_set got_wpsinfo=%d", p->ifname, p->wps_info); -+ system( p->cmd ); -+} -+ -+void p2p_pincode(struct p2p *p, char *ins_no, char *ins_no_again) -+{ -+ int pin_check=0; -+ p->p2p_get=0; -+ p->show_scan_result = 1; -+ ui_screen(p); -+ printf("%s", ins_no); -+ scanf("%d",&pin_check); -+ while( wps_pin_checksum(pin_check) != 0 ) -+ { -+ p->show_scan_result = 1; -+ ui_screen(p); -+ printf("%s", ins_no_again); -+ scanf("%d",&pin_check); -+ } -+ p->pin = pin_check; -+} -+ -+void p2p_devaddr(struct p2p *p) -+{ -+ int c; -+ struct scan *pscan_pool; -+ -+ p->p2p_get=0; -+ -+ scanf("%d", &c); -+ pscan_pool = &p->scan_pool[c-1]; -+ strncpy(p->peer_devaddr, pscan_pool->addr, 17); -+ -+ if( pscan_pool->go == 1) -+ p->connect_go = 1; -+} -+ -+void p2p_role(struct p2p *p, int flag) -+{ -+ FILE *pf=NULL; -+ -+ memset( p->cmd, 0x00, CMD_SZ ); -+ sprintf( p->cmd, "iwpriv %s p2p_get role > status.txt", p->ifname); -+ system( p->cmd ); -+ -+ pf = fopen( "./status.txt", "r" ); -+ if ( pf ) -+ { -+ while( !feof( pf ) ){ -+ memset( p->parse, 0x00, CMD_SZ ); -+ fgets( p->parse, CMD_SZ, pf ); -+ if( strncmp( p->parse, "Role", 4) == 0 ) -+ { -+ p->role = atoi( &p->parse[ 5 ] ); -+ if(flag==1){ -+ p->p2p_get=1; -+ sprintf( p->print_line, "Role=%s", naming_role(p->role)); -+ } -+ break; -+ } -+ } -+ fclose( pf ); -+ } -+} -+ -+void p2p_status(struct p2p *p, int flag) -+{ -+ FILE *pf=NULL; -+ -+ memset( p->cmd, 0x00, CMD_SZ ); -+ sprintf( p->cmd, "iwpriv %s p2p_get status > status.txt", p->ifname); -+ system( p->cmd ); -+ -+ pf = fopen( "./status.txt", "r" ); -+ if ( pf ) -+ { -+ while( !feof( pf ) ){ -+ memset( p->parse, 0x00, CMD_SZ ); -+ fgets( p->parse, CMD_SZ, pf ); -+ if( strncmp( p->parse, "Status", 6) == 0 ) -+ { -+ p->status = atoi( &p->parse[ 7 ] ); -+ if(flag==1){ -+ p->p2p_get=1; -+ sprintf( p->print_line, "Status=%s", naming_status(p->status)); -+ } -+ break; -+ } -+ } -+ fclose( pf ); -+ } -+} -+ -+void change_hostapd_op_ch(struct p2p *p, int op_ch) -+{ -+ FILE *pfin = NULL; -+ FILE *pfout = NULL; -+ char parse[CMD_SZ] = { 0x00 }; -+ char cmd[CMD_SZ] = { 0x00 }; -+ -+ pfin = fopen( p->ap_conf, "r" ); -+ pfout = fopen( "./p2p_hostapd_temp.conf", "w" ); -+ -+ if( pfin && pfout ) -+ { -+ while( !feof( pfin ) ){ -+ memset( parse, 0x00, CMD_SZ ); -+ fgets( parse, CMD_SZ, pfin ); -+ -+ if(strncmp(parse, "channel=", 8) == 0) -+ { -+ memset(parse, 0x00, CMD_SZ); -+ sprintf( parse, "channel=%d\n", op_ch ); -+ fputs( parse, pfout ); -+ } -+ else -+ fputs(parse, pfout); -+ } -+ } -+ else -+ { -+ return; -+ } -+ -+ if( pfin != NULL ) -+ fclose( pfin ); -+ if( pfout != NULL ) -+ fclose( pfout ); -+ -+ memset( cmd, 0x00, CMD_SZ); -+ sprintf( cmd, "rm -rf %s", p->ap_conf ); -+ system( cmd ); -+ memset( cmd, 0x00, CMD_SZ); -+ sprintf( cmd, "mv ./p2p_hostapd_temp.conf %s", p->ap_conf ); -+ system( cmd ); -+ -+ return; -+} -+ -+void p2p_get_opch(struct p2p *p) -+{ -+ FILE *pf=NULL; -+ int peer_op_ch = 0; -+ -+ memset( p->cmd, 0x00, CMD_SZ ); -+ sprintf( p->cmd, "iwpriv %s p2p_get op_ch > cm.txt", p->ifname); -+ system( p->cmd ); -+ -+ pf = fopen( "./cm.txt", "r" ); -+ if ( pf ) -+ { -+ while( !feof( pf ) ){ -+ memset( p->parse, 0x00, CMD_SZ ); -+ fgets( p->parse, CMD_SZ, pf ); -+ if( strncmp( p->parse, "Op_ch", 5) == 0 ) -+ { -+ peer_op_ch = atoi( &p->parse[ 6 ] ); -+ if( peer_op_ch != p->op_ch ) -+ { -+ change_hostapd_op_ch( p, peer_op_ch ); -+ } -+ break; -+ } -+ } -+ fclose( pf ); -+ } -+} -+ -+void p2p_prov_disc_no_addr(struct p2p *p, char *msg) -+{ -+ p->p2p_get=1; -+ memset( p->print_line, 0x00, CMD_SZ ); -+ sprintf( p->print_line, "%s", msg); -+} -+ -+#ifdef P2P_AUTO -+void p2p_prov_disc(struct p2p *p, char *msg, char *dis_msg, char *label_msg) -+{ -+ int wps_cm, retry_count=0; -+ char prov[100] = { 0x00 }; -+ -+ p->p2p_get=0; -+ p->show_scan_result = 1; -+ ui_screen(p); -+ printf("%s", msg); -+ scanf("%d",&wps_cm); -+ -+ if(p->res == 0) -+ { -+ p->res = 1; -+ } -+ -+ memset( p->cmd, 0x00, CMD_SZ ); -+ if( wps_cm == 0 ) -+ sprintf( p->cmd, "iwpriv %s p2p_set prov_disc=%s_display", p->ifname, p->peer_devaddr); -+ else if( wps_cm == 1 ) -+ sprintf( p->cmd, "iwpriv %s p2p_set prov_disc=%s_keypad", p->ifname, p->peer_devaddr); -+ else if( wps_cm == 2 ) -+ sprintf( p->cmd, "iwpriv %s p2p_set prov_disc=%s_pbc", p->ifname, p->peer_devaddr); -+ else if( wps_cm == 3 ) -+ sprintf( p->cmd, "iwpriv %s p2p_set prov_disc=%s_label", p->ifname, p->peer_devaddr); -+ system( p->cmd ); -+ strcpy( prov, p->cmd ); -+ -+ usleep(500000); -+ p2p_status( p, 0 ); -+ -+ while( p->status != P2P_STATE_RX_PROVISION_DIS_RSP && retry_count < MAX_PROV_RETRY) -+ { -+ usleep( PROV_WAIT_TIME ); -+ retry_count++; -+ p2p_status( p, 0 ); -+ if( (retry_count % PROV_RETRY_INTERVAL) == 0) -+ system( prov ); -+ } -+ -+ if( p->status == P2P_STATE_RX_PROVISION_DIS_RSP ) -+ { -+ switch(wps_cm) -+ { -+ case 0: p->wps_info=1; break; -+ case 1: p->wps_info=2; break; -+ case 2: p->wps_info=3; break; -+ case 3: p->wps_info=1; break; -+ } -+ -+ if( wps_cm==1 || wps_cm==2 ) -+ { -+ p2p_wpsinfo(p); -+ -+ if(p->connect_go == 1) -+ p2p_client_mode(p); -+ else -+ p2p_set_nego(p); -+ } -+ else if( wps_cm==0 || wps_cm==3 ) -+ { -+ ui_screen(p); -+ if( wps_cm ==0 ) -+ printf("%s", dis_msg); -+ else if( wps_cm == 3 ) -+ printf("%s", label_msg); -+ scanf("%d",&p->pin); -+ -+ p2p_wpsinfo(p); -+ -+ if(p->connect_go == 1) -+ p2p_client_mode(p); -+ else -+ p2p_set_nego(p); -+ -+ } -+ } -+ else -+ { -+ p->p2p_get = 1; -+ memset( p->print_line, 0x00, CMD_SZ ); -+ sprintf( p->print_line, "Issue provision discovery fail" ); -+ ui_screen(p); -+ -+#ifdef P2P_AUTO -+ pthread_create(&p->pthread, NULL, &polling_status, (void *)p); -+#endif -+ -+ } -+ -+} -+#else -+ -+// This mode is without the following procedures: -+// 1.set config method -+// 2.start group negotiation -+// 3.start wpa_supplicant or hostapd -+void p2p_prov_disc(struct p2p *p, char *msg, char *dis_msg, char *label_msg) -+{ -+ int wps_cm; -+ p->p2p_get=0; -+ p->show_scan_result = 1; -+ ui_screen(p); -+ printf("%s", msg); -+ scanf("%d",&wps_cm); -+ memset( p->cmd, 0x00, CMD_SZ ); -+ -+ -+ if( wps_cm == 0 ) -+ sprintf( p->cmd, "iwpriv %s p2p_set prov_disc=%s_display", p->ifname, p->peer_devaddr); -+ else if( wps_cm == 1 ) -+ sprintf( p->cmd, "iwpriv %s p2p_set prov_disc=%s_keypad", p->ifname, p->peer_devaddr); -+ else if( wps_cm == 2 ) -+ sprintf( p->cmd, "iwpriv %s p2p_set prov_disc=%s_pbc", p->ifname, p->peer_devaddr); -+ else if( wps_cm == 3 ) -+ sprintf( p->cmd, "iwpriv %s p2p_set prov_disc=%s_label", p->ifname, p->peer_devaddr); -+ system( p->cmd ); -+ -+} -+#endif -+ -+void p2p_set_nego(struct p2p *p) -+{ -+ FILE *pf=NULL; -+ int retry_count = 0, success = 0; -+ int retry = NEGO_RETRY_INTERVAL, query = NEGO_QUERY_INTERVAL; -+ -+ p->p2p_get=1; -+ memset( p->print_line, 0x00, CMD_SZ ); -+ strcpy( p->print_line, p->nego_msg); -+ ui_screen(p); -+ -+ memset( p->cmd, 0x00, CMD_SZ ); -+ sprintf( p->cmd, "iwpriv %s p2p_set nego=%s ", p->ifname, p->peer_devaddr); -+ system( p->cmd ); -+ -+ usleep( PRE_NEGO_INTERVAL ); -+ -+ p2p_status(p, 0); -+ -+ while( !p2p_check_success(p) && (retry_count < 120 / NEGO_QUERY_INTERVAL )) -+ { -+ retry_count++; -+ -+ if( (retry_count % ( retry / query ) )==0 ) -+ { -+ memset( p->cmd, 0x00, CMD_SZ ); -+ sprintf( p->cmd, "iwpriv %s p2p_set nego=%s ", p->ifname, p->peer_devaddr); -+ system( p->cmd ); -+ -+ usleep( NEGO_QUERY_INTERVAL ); -+ p2p_status(p, 1); -+ } -+ else -+ { -+ ui_screen(p); -+ usleep( NEGO_QUERY_INTERVAL ); -+ p2p_status(p, 1); -+ } -+ } -+ -+ if( p2p_check_success(p) ) -+ { -+ p2p_role(p ,0); -+ p->p2p_get = 1; -+ memset( p->print_line, 0x00, CMD_SZ ); -+ sprintf( p->print_line, "%s", p->ok_msg ); -+ p2p_ifaddr(p); -+ ui_screen(p); -+ -+ if( p->role == P2P_ROLE_CLIENT ) -+ { -+ p2p_client_mode(p); -+ } -+ else if( p->role == P2P_ROLE_GO ) -+ { -+ p2p_get_opch(p); -+ p2p_go_mode(p); -+ } -+ } -+ else -+ { -+ p->p2p_get = 1; -+ p2p_status(p, 0); -+ memset( p->print_line, 0x00, CMD_SZ ); -+ sprintf( p->print_line, "Status= %d, %s", p->status, p->fail_msg ); -+ ui_screen(p); -+ -+#ifdef P2P_ATUO -+ pthread_create(&p->pthread, NULL, &polling_status, (void *)p); -+#endif -+ -+ } -+} -+ -+//After negotiation success, get peer device's interface address. -+void p2p_ifaddr(struct p2p *p) -+{ -+ FILE *pf=NULL; -+ char addr_12[12] = { 0x00 }; -+ int i; -+ -+ /* peer_ifaddr */ -+ memset( p->cmd, 0x00, CMD_SZ ); -+ sprintf( p->cmd, "iwpriv %s p2p_get peer_ifa > status.txt", p->ifname); -+ system( p->cmd ); -+ -+ pf = fopen( "./status.txt", "r" ); -+ if ( pf ) -+ { -+ while( !feof( pf ) ){ -+ memset( p->parse, 0x00, CMD_SZ ); -+ fgets( p->parse, CMD_SZ, pf ); -+ if( strncmp( p->parse, "MAC", 3) == 0 ) -+ { -+ strncpy( p->peer_ifaddr, p->parse+4, 17 ); -+ break; -+ } -+ } -+ fclose( pf ); -+ } -+ -+} -+ -+void p2p_client_mode(struct p2p *p) -+{ -+ FILE *pf = NULL; -+ int count = 0, ret = 0; -+ int inactive_count = 0, inactive_restart = 0; -+ -+ if(p->wpa_open==_TRUE) -+ return; -+ else -+ p->wpa_open = _TRUE; -+ -+ p2p_ifaddr(p); -+ -+ memset( p->cmd, 0x00, CMD_SZ ); -+ sprintf( p->cmd, "%s -i %s -c %s -B ",p->wpa_path, p->ifname, p->wpa_conf); -+ system( p->cmd ); -+ -+ p->p2p_get=1; -+ memset( p->print_line, 0x00, CMD_SZ ); -+ strcpy( p->print_line, "Start wpa_supplicant"); -+ ui_screen(p); -+ -+ usleep( SUPPLICANT_INIT_TIME ); -+ -+ do_wps(p); -+ -+ usleep( SUPPLICANT_INTERVAL ); -+ -+ while( count < WPS_RETRY ) //query status -+ { -+ -+ memset( p->cmd, 0x00, CMD_SZ ); -+ sprintf( p->cmd, "%s status > supp_status.txt", p->wpacli_path); -+ system( p->cmd ); -+ -+ pf = fopen( "./supp_status.txt", "r" ); -+ if ( pf ) -+ { -+ while( !feof( pf ) ){ -+ memset( p->parse, 0x00, CMD_SZ ); -+ fgets( p->parse, CMD_SZ, pf ); -+ if( strncmp( p->parse, "wpa_state=", 10) == 0 ) -+ { -+ int i; -+ if( strncmp( p->parse, "wpa_state=COMPLETED", 19) == 0 ){ -+ count = WPS_RETRY; -+ p->wpsing = _FALSE; -+#ifdef DHCP -+ memset( p->cmd, 0x00, CMD_SZ ); -+ sprintf( p->cmd, "dhclient %s", p->ifname); -+ system( p->cmd ); -+#endif //DHCP -+ } -+ else if( strncmp( p->parse, "wpa_state=INACTIVE", 18) == 0 ){ -+ inactive_count++; -+ if( (inactive_count % 5)== 0) -+ { -+ if( p->wps_info == 2 ) -+ { -+ memset( p->cmd, 0x00, CMD_SZ ); -+ sprintf( p->cmd, "%s wps_pin %s %d > supp_status.txt ", p->wpacli_path, p->peer_ifaddr, p->pin); -+ system( p->cmd ); -+ -+ inactive_restart = 1; -+ } -+ } -+ } -+ -+ if( inactive_restart == 1 ) -+ { -+ inactive_restart = 0; -+ p->p2p_get=1; -+ memset(p->print_line, 0x00, CMD_SZ); -+ sprintf(p->print_line, "Restart WPS"); -+ ui_screen(p); -+ } -+ else -+ { -+ p->p2p_get=1; -+ memset(p->print_line, 0x00, CMD_SZ); -+ for(i=0; iparse[i] == '\n'){ -+ p->parse[i] = ' '; -+ } -+ } -+ sprintf(p->print_line, "%s", p->parse); -+ ui_screen(p); -+ } -+ -+ break; -+ } -+ } -+ -+ fclose( pf ); -+ } -+ -+ count++; -+ usleep( SUPPLICANT_INTERVAL ); -+ -+ } -+ -+ p->wpsing = _FALSE; -+} -+ -+void p2p_go_mode(struct p2p *p) -+{ -+ int count = 0, i = -1; -+ char addr_lower[18]; -+ -+ p2p_ifaddr(p); -+ p->no_sta_connected++; -+ -+ p->p2p_get=1; -+ memset( p->print_line, 0x00, CMD_SZ ); -+ strcpy( p->print_line, "Start hostapd"); -+ ui_screen(p); -+ -+ if(p->ap_open != _TRUE) -+ { -+ memset( p->cmd, 0x00, CMD_SZ ); -+ sprintf( p->cmd, "%s -B %s > temp.txt",p->ap_path, p->ap_conf); -+ system( p->cmd ); -+ -+ usleep( HOSTAPD_INIT_TIME ); -+ p->ap_open = _TRUE; -+ } -+ -+ do_wps(p); -+ -+ usleep( HOSTAPD_INTERVAL ); -+ -+ -+ while( count < WPS_RETRY ) //query status -+ { -+ if( read_all_sta(p) == _TRUE ) -+ { -+ count = WPS_RETRY; -+ p->wpsing = _FALSE; -+ -+ p->p2p_get=1; -+ memset(p->print_line, 0x00, CMD_SZ); -+ for(i=0; iparse[i] == '\n'){ -+ p->parse[i] = ' '; -+ } -+ } -+ sprintf(p->print_line, "%s", p->parse); -+ ui_screen(p); -+#ifdef DHCP -+ memset( p->cmd, 0x00, CMD_SZ ); -+ sprintf( p->cmd, "ifconfig %s 192.168.1.254", p->ifname); -+ system( p->cmd ); -+ -+ usleep(50000); -+ -+ system( "/etc/rc.d/init.d/dhcpd start" ); -+ system( "clear" ); -+#endif //DHCP -+ -+ //After starting hostapd and doing WPS connection successful, -+ //We create a thread to query driver if some other p2p devices connected. -+ p2p_status(p, 0); -+ usleep(50000); -+ -+#ifdef P2P_AUTO -+ p->res_go = pthread_create(&p->pthread_go, NULL, &polling_client, (void *)p); -+ -+ if( p->res_go != 0 ) -+ { -+ p->p2p_get=1; -+ memset( p->print_line, 0x00, CMD_SZ ); -+ sprintf( p->print_line, "Thread creation failed" ); -+ } -+#endif -+ break; -+ } -+ else -+ { -+ if( count == WPS_RETRY) -+ break; -+ -+ count++; -+ usleep( HOSTAPD_INTERVAL ); -+ -+ p->p2p_get=1; -+ memset( p->print_line, 0x00, CMD_SZ ); -+ sprintf( p->print_line, "hostapd open, count:%d", count); -+ ui_screen(p); -+ } -+ } -+ -+ p->wpsing = _FALSE; -+} -+ -+void p2p_get_hostapd_conf(struct p2p *p) -+{ -+ FILE *pf = NULL; -+ -+ pf = fopen( p->ap_conf, "r" ); -+ if ( pf ) -+ { -+ while( !feof( pf ) ){ -+ memset(p->parse, 0x00, CMD_SZ); -+ fgets(p->parse, CMD_SZ, pf); -+ if(strncmp(p->parse, "ssid=", 5) == 0) -+ { -+ strcpy( p->apd_ssid, p->parse+5 ); -+ } -+ else if(strncmp(p->parse, "channel=", 8) == 0) -+ { -+ p->op_ch = atoi( p->parse+8 ); -+ } -+ else if(strncmp(p->parse, "device_name=", 12) == 0) -+ { -+ int i; -+ p->dev_name[0] = '"'; -+ strncpy( p->dev_name+1, p->parse+12, 32 ); -+ for(i=31; i>0; i--) -+ { -+ if(p->dev_name[i] == '\n') -+ { -+ p->dev_name[i]='"'; -+ p->dev_name[i+1]=' '; -+ break; -+ } -+ } -+ } -+ } -+ -+ fclose( pf ); -+ } -+ -+} -+ -+void p2p_set_opch(struct p2p *p, char *msg, int print) -+{ -+ if(print == 1) -+ { -+ p->show_scan_result = 1; -+ ui_screen(p); -+ printf("%s", msg); -+ scanf("%d",&p->op_ch); -+ } -+ -+ memset( p->cmd, 0x00, CMD_SZ ); -+ sprintf( p->cmd, "iwpriv %s p2p_set op_ch=%d", p->ifname, p->op_ch); -+ system( p->cmd ); -+} -+ -+void p2p_softap_ssid(struct p2p *p, char *msg, int print) -+{ -+ if(print == 1) -+ { -+ p->show_scan_result = 1; -+ ui_screen(p); -+ printf("%s", msg); -+ scanf("%s",p->apd_ssid); -+ } -+ -+ memset( p->cmd, 0x00, CMD_SZ ); -+ sprintf( p->cmd, "iwpriv %s p2p_set ssid=%s ", p->ifname, p->apd_ssid); -+ system( p->cmd ); -+} -+ -+void p2p_listen_ch(struct p2p *p, char *msg) -+{ -+ p->show_scan_result = 1; -+ ui_screen(p); -+ printf("%s", msg); -+ scanf("%d",&p->listen_ch); -+ -+ memset( p->cmd, 0x00, CMD_SZ ); -+ sprintf( p->cmd, "iwpriv %s p2p_set listen_ch=%d ", p->ifname, p->listen_ch); -+ system( p->cmd ); -+} -+ -+//When receive provision discovery request, -+//it can show which device address that are connected. -+void p2p_peer_devaddr(struct p2p *p, char *peer_devaddr) -+{ -+ FILE *pf = NULL; -+ char addr_12[12] = { 0x00 }; -+ int i; -+ -+ memset( p->cmd, 0x00, CMD_SZ ); -+ sprintf( p->cmd, "iwpriv %s p2p_get peer_deva > peer.txt", p->ifname); -+ system( p->cmd ); -+ -+ pf = fopen( "./peer.txt", "r" ); -+ if ( pf ) -+ { -+ memset( p->parse, 0x00, CMD_SZ ); -+ fgets( p->parse, CMD_SZ, pf ); -+ fgets( p->parse, CMD_SZ, pf ); -+ strncpy(addr_12, p->parse, 12 ); -+ -+ for(i=0; i<6; i++) -+ { -+ p->peer_devaddr[3*i] = addr_12[2*i]; -+ p->peer_devaddr[3*i+1] = addr_12[2*i+1]; -+ -+ if(i==5) -+ p->peer_devaddr[3*i+2] = '\0'; -+ else -+ p->peer_devaddr[3*i+2] = ':'; -+ } -+ -+ fclose( pf ); -+ -+ } -+ -+} -+ -+//When receive provision discovery request, -+//it can show which config method that want to be as WPS connection. -+void p2p_peer_req_cm(struct p2p *p, char *peer_req_cm) -+{ -+ FILE *pf = NULL; -+ -+ memset( p->cmd, 0x00, CMD_SZ ); -+ sprintf( p->cmd, "iwpriv %s p2p_get req_cm > peer.txt", p->ifname); -+ system( p->cmd ); -+ -+ pf = fopen( "./peer.txt", "r" ); -+ if ( pf ) -+ { -+ while( !feof( pf ) ){ -+ memset( p->parse, 0x00, CMD_SZ ); -+ fgets( p->parse, CMD_SZ, pf ); -+ if( strncmp( p->parse, "CM", 2) == 0 ) -+ { -+ strncpy( peer_req_cm, p->parse+3, 3 ); -+ break; -+ } -+ } -+ fclose( pf ); -+ } -+ -+} -+ -+//When be regotiated passsively and successfully, -+//it will show peer device's peer device address and request config method -+void p2p_peer_info(struct p2p *p, char *peer_devaddr, char *peer_req_cm) -+{ -+ p->p2p_get=1; -+ -+ memset( p->print_line, 0x00, CMD_SZ ); -+ sprintf( p->print_line, "Peer address:%s, req_cm: %s ", peer_devaddr, peer_req_cm); -+ -+} -+ -+//After scan, it will get other devices' supported config methods. -+void p2p_wps_cm(struct p2p *p, char *scan_addr, char *cms) -+{ -+ FILE *pf = NULL; -+ int cm=0, i=0; -+ char parse[100] = {0x00}; -+ memset( cms, 0x00, 30 ); -+ -+ memset( p->cmd, 0x00, CMD_SZ ); -+ sprintf( p->cmd, "iwpriv %s p2p_get2 wpsCM=%s > cm.txt", p->ifname, scan_addr); -+ system( p->cmd ); -+ -+ pf = fopen( "./cm.txt", "r" ); -+ if ( pf ) -+ { -+ while( !feof( pf ) ){ -+ memset( parse, 0x00, CMD_SZ ); -+ fgets( parse, CMD_SZ, pf ); -+ if( strncmp( parse, "M=", 2 ) == 0 ) -+ { -+ cm = atoi( &parse[ 2 ] ); -+ -+ if((cm & WPS_CONFIG_METHOD_LABEL) == WPS_CONFIG_METHOD_LABEL){ -+ strncpy( cms+i, " LAB", 4 ); -+ i=i+4; -+ } -+ if((cm & WPS_CONFIG_METHOD_DISPLAY) == WPS_CONFIG_METHOD_DISPLAY){ -+ if((cm & WPS_CONFIG_METHOD_VDISPLAY) == WPS_CONFIG_METHOD_VDISPLAY){ -+ strncpy( cms+i, " VDIS", 5 ); -+ i=i+5; -+ }else if((cm & WPS_CONFIG_METHOD_PDISPLAY) == WPS_CONFIG_METHOD_PDISPLAY){ -+ strncpy( cms+i, " PDIS", 5 ); -+ i=i+5; -+ }else{ -+ strncpy( cms+i, " DIS", 4 ); -+ i=i+4; -+ } -+ } -+ if((cm & WPS_CONFIG_METHOD_E_NFC) == WPS_CONFIG_METHOD_E_NFC){ -+ strncpy( cms+i, " ENFC", 5 ); -+ i=i+5; -+ } -+ if((cm & WPS_CONFIG_METHOD_I_NFC) == WPS_CONFIG_METHOD_I_NFC){ -+ strncpy( cms+i, " INFC", 5 ); -+ i=i+5; -+ } -+ if((cm & WPS_CONFIG_METHOD_NFC) == WPS_CONFIG_METHOD_NFC){ -+ strncpy( cms+i, " NFC", 4 ); -+ i=i+4; -+ } -+ if((cm & WPS_CONFIG_METHOD_PBC) == WPS_CONFIG_METHOD_PBC){ -+ if((cm & WPS_CONFIG_METHOD_VPBC) == WPS_CONFIG_METHOD_VPBC){ -+ strncpy( cms+i, " VPBC", 5 ); -+ i=i+5; -+ }else if((cm & WPS_CONFIG_METHOD_PPBC) == WPS_CONFIG_METHOD_PPBC){ -+ strncpy( cms+i, " PPBC", 5 ); -+ i=i+5; -+ }else{ -+ strncpy( cms+i, " PBC", 4 ); -+ i=i+4; -+ } -+ } -+ if((cm & WPS_CONFIG_METHOD_KEYPAD) == WPS_CONFIG_METHOD_KEYPAD){ -+ strncpy( cms+i, " PAD", 4 ); -+ i=i+4; -+ } -+ -+ break; -+ } -+ } -+ fclose( pf ); -+ } -+ -+} -+ -+//After scan, it will get other devices' device name. -+void p2p_device_name(struct p2p *p, char *scan_addr, char *dns) -+{ -+ FILE *pf = NULL; -+ int i; -+ char parse[100] = {0x00}; -+ memset( dns, 0x00, 32 ); -+ -+ memset( p->cmd, 0x00, CMD_SZ ); -+ sprintf( p->cmd, "iwpriv %s p2p_get2 devN=%s > cm.txt", p->ifname, scan_addr); -+ system( p->cmd ); -+ -+ pf = fopen( "./cm.txt", "r" ); -+ if ( pf ) -+ { -+ while( !feof( pf ) ){ -+ memset( parse, 0x00, CMD_SZ ); -+ fgets( parse, CMD_SZ, pf ); -+ if( strncmp( parse, "N=", 2) == 0 ) -+ { -+ strncpy( dns, parse+2, 32); -+ for( i=0; i<32; i++) -+ { -+ if(*(dns+i) == '\n'){ -+ *(dns+i) = ' ' ; -+ break; -+ } -+ } -+ -+ break; -+ } -+ } -+ fclose( pf ); -+ } -+} -+ -+//Successively query local device status with interval "POLLING_INTERVAL" -+//when status == P2P_STATE_RX_PROVISION_DIS_REQ, -+//it require user to insert corresponding WPS config method -+void *polling_status(void *arg) -+{ -+ struct p2p *p=(struct p2p*)arg; -+ -+ while( p->res == 0 ){ -+ -+ p2p_status(p, 0); -+ if( (p->status == P2P_STATE_RX_PROVISION_DIS_REQ) || (p->status == P2P_STATE_GONEGO_FAIL) ) -+ { -+ p->thread_trigger = THREAD_DEVICE ; -+ -+ char peer_devaddr[18]; -+ char peer_req_cm[4]; -+ -+ memset( peer_devaddr, 0x00, 18); -+ memset( peer_req_cm, 0x00, 4); -+ -+ p2p_peer_devaddr(p, peer_devaddr); -+ p2p_peer_req_cm(p, peer_req_cm); -+ p2p_peer_info(p, p->peer_devaddr, peer_req_cm); -+ -+ ui_screen(p); -+ -+ //strncpy(p->peer_devaddr, peer_devaddr, 17); -+ if( (strncmp( peer_req_cm, "dis", 3) == 0) || (strncmp( peer_req_cm, "lab", 3) == 0) ) -+ { -+ printf("Here is your PIN, insert c to continue: %d\n", p->pin); -+ } -+ else if( (strncmp( peer_req_cm, "pbc", 3) == 0) ) -+ { -+ printf("Please push b to accept:\n"); -+ } -+ else if( (strncmp( peer_req_cm, "pad", 3) == 0) ) -+ { -+ printf("Please insert peer PIN code:\n"); -+ } -+ -+ break; -+ } -+ -+ usleep( POLLING_INTERVAL ); -+ } -+ -+ return NULL; -+} -+ -+//If p2p device becomes GO, we still polling driver status -+//to check whether some other p2p devices connected -+void *polling_client(void *arg) -+{ -+ struct p2p *p=(struct p2p*)arg; -+ -+ while( p->res_go == 0 ){ -+ -+ if( p->no_sta_connected > 0 && ( p->wpsing == _FALSE ) ) -+ { -+ if( read_all_sta(p) == _FALSE ) -+ { -+ p->no_sta_connected--; -+ } -+ } -+ -+ p2p_status(p, 0); -+ if( p->status == P2P_STATE_RX_PROVISION_DIS_REQ || p->status == P2P_STATE_GONEGO_FAIL || p->status == P2P_STATE_GONEGO_ING ) -+ { -+ p->thread_trigger = THREAD_GO ; -+ -+ char peer_devaddr[18]; -+ char peer_req_cm[4]; -+ -+ memset( peer_devaddr, 0x00, 18); -+ memset( peer_req_cm, 0x00, 4); -+ -+ p2p_peer_devaddr(p, peer_devaddr); -+ p2p_peer_req_cm(p, peer_req_cm); -+ p2p_peer_info(p, p->peer_devaddr, peer_req_cm); -+ -+ ui_screen(p); -+ -+ //strncpy(p->peer_devaddr, peer_devaddr, 17); -+ if( (strncmp( peer_req_cm, "dis", 3) == 0) || (strncmp( peer_req_cm, "lab", 3) == 0) ) -+ { -+ printf("Here is your PIN, insert c to continue: %d\n", p->pin); -+ } -+ else if( (strncmp( peer_req_cm, "pbc", 3) == 0) ) -+ { -+ printf("Please push b to accept:\n", p->status); -+ } -+ else if( (strncmp( peer_req_cm, "pad", 3) == 0) ) -+ { -+ printf("Please insert peer PIN code:\n"); -+ } -+ -+ break; -+ } -+ -+ usleep( POLLING_INTERVAL ); -+ } -+ -+ return NULL; -+} -diff --git linux-5.8/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/p2p_test.h linux-5.8/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/p2p_test.h -new file mode 100644 -index 000000000..0dbae3c1d ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/p2p_test.h -@@ -0,0 +1,167 @@ -+#ifndef _P2P_UI_TEST_H_ -+#define _P2P_UI_TEST_H_ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#define P2P_AUTO 1 -+//#define DHCP 1 -+#define CMD_SZ 100 -+#define SSID_SZ 32 -+ -+#define SEC 1000000 -+#define SCAN_POOL_NO 8 -+#define NEGO_RETRY_INTERVAL 10 * SEC -+#define NEGO_QUERY_INTERVAL 0.5 * SEC -+#define PRE_NEGO_INTERVAL 0.5 * SEC -+#define MAX_PROV_RETRY 15 -+#define PROV_RETRY_INTERVAL 5 -+#define PROV_WAIT_TIME 1 * SEC -+#define MAX_NEGO_RETRY 60 -+#define NEGO_WAIT_TIME 0.5 * SEC -+#define WPS_RETRY 120 -+#define SUPPLICANT_INIT_TIME 1 * SEC -+#define HOSTAPD_INIT_TIME 1 * SEC -+#define SUPPLICANT_INTERVAL 1 * SEC -+#define HOSTAPD_INTERVAL 1 * SEC -+#define POLLING_INTERVAL 1 * SEC -+#define _TRUE 1 -+#define _FALSE 0 -+ -+#define WPS_CONFIG_METHOD_LABEL 0x0004 -+#define WPS_CONFIG_METHOD_DISPLAY 0x0008 -+#define WPS_CONFIG_METHOD_E_NFC 0x0010 -+#define WPS_CONFIG_METHOD_I_NFC 0x0020 -+#define WPS_CONFIG_METHOD_NFC 0x0040 -+#define WPS_CONFIG_METHOD_PBC 0x0080 -+#define WPS_CONFIG_METHOD_KEYPAD 0x0100 -+#define WPS_CONFIG_METHOD_VPBC 0x0280 -+#define WPS_CONFIG_METHOD_PPBC 0x0480 -+#define WPS_CONFIG_METHOD_VDISPLAY 0x2008 -+#define WPS_CONFIG_METHOD_PDISPLAY 0x4008 -+ -+enum thread_trigger{ -+ THREAD_NONE = 0, -+ THREAD_DEVICE = 1, -+ THREAD_GO = 2, -+}; -+ -+enum P2P_ROLE { -+ P2P_ROLE_DISABLE = 0, -+ P2P_ROLE_DEVICE = 1, -+ P2P_ROLE_CLIENT = 2, -+ P2P_ROLE_GO = 3 -+}; -+ -+enum P2P_STATE { -+ P2P_STATE_NONE = 0, // P2P disable -+ P2P_STATE_IDLE = 1, // P2P had enabled and do nothing -+ P2P_STATE_LISTEN = 2, // In pure listen state -+ P2P_STATE_SCAN = 3, // In scan phase -+ P2P_STATE_FIND_PHASE_LISTEN = 4, // In the listen state of find phase -+ P2P_STATE_FIND_PHASE_SEARCH = 5, // In the search state of find phase -+ P2P_STATE_TX_PROVISION_DIS_REQ = 6, // In P2P provisioning discovery -+ P2P_STATE_RX_PROVISION_DIS_RSP = 7, -+ P2P_STATE_RX_PROVISION_DIS_REQ = 8, -+ P2P_STATE_GONEGO_ING = 9, // Doing the group owner negoitation handshake -+ P2P_STATE_GONEGO_OK = 10, // finish the group negoitation handshake with success -+ P2P_STATE_GONEGO_FAIL = 11, // finish the group negoitation handshake with failure -+ P2P_STATE_RECV_INVITE_REQ = 12, // receiving the P2P Inviation request -+ P2P_STATE_PROVISIONING_ING = 13, // Doing the P2P WPS -+ P2P_STATE_PROVISIONING_DONE = 14, // Finish the P2P WPS -+}; -+ -+enum P2P_WPSINFO { -+ P2P_NO_WPSINFO = 0, -+ P2P_GOT_WPSINFO_PEER_DISPLAY_PIN = 1, -+ P2P_GOT_WPSINFO_SELF_DISPLAY_PIN = 2, -+ P2P_GOT_WPSINFO_PBC = 3, -+}; -+ -+struct scan{ -+ char addr[18]; -+ int go; -+}; -+ -+struct p2p{ -+ char ifname[10]; -+ int enable; -+ int status; -+ char dev_name[33]; -+ int intent; -+ int listen_ch; -+ int wps_info; -+ int wpsing; -+ unsigned int pin; -+ int role; -+ char peer_devaddr[18]; -+ int p2p_get; //p2p_get==1 : print messages from ioctl p2p_get -+ char print_line[CMD_SZ]; -+ int have_p2p_dev; //have_p2p_dev==1 : after scanning p2p device -+ int show_scan_result; -+ int count_line; -+ char peer_ifaddr[18]; -+ char cmd[CMD_SZ]; -+ char parse[CMD_SZ]; -+ char apd_ssid[SSID_SZ]; -+ int op_ch; //operation channel -+ int wpa_open; -+ int ap_open; -+ char ap_conf[CMD_SZ]; -+ char ap_path[CMD_SZ]; -+ char apcli_path[CMD_SZ]; -+ char wpa_conf[CMD_SZ]; -+ char wpa_path[CMD_SZ]; -+ char wpacli_path[CMD_SZ]; -+ char ok_msg[CMD_SZ]; -+ char redo_msg[CMD_SZ]; -+ char fail_msg[CMD_SZ]; -+ char nego_msg[CMD_SZ]; -+ char scan_msg[CMD_SZ]; -+ int thread_trigger; -+ pthread_t pthread; -+ pthread_t pthread_go; -+ int res; //check if thread is created; 1: disabled, 0: enabled -+ int res_go; //created if p2p device becomes GO -+ struct scan scan_pool[SCAN_POOL_NO]; -+ int connect_go; -+ int no_sta_connected; -+}; -+ -+void ui_screen(struct p2p *p); -+char *naming_wpsinfo(int wps_info); -+char *naming_role(int role); -+char *naming_status(int status); -+unsigned int wps_pin_checksum(unsigned int pin); -+void p2p_enable(struct p2p *p); -+void p2p_scan(struct p2p *p); -+void scan_result(struct p2p *p); -+void p2p_intent(struct p2p *p); -+void p2p_pincode(struct p2p *p, char *ins_no, char *ins_no_again); -+void p2p_devaddr(struct p2p *p); -+void p2p_role(struct p2p *p, int flag); -+void p2p_status(struct p2p *p, int flag); -+void p2p_prov_disc_no_addr(struct p2p *p, char *msg); -+void p2p_prov_disc(struct p2p *p, char *msg, char *dis_msg, char *label_msg); -+void p2p_set_nego(struct p2p *p); -+void p2p_ifaddr(struct p2p *p); -+void p2p_client_mode(struct p2p *p); -+void p2p_go_mode(struct p2p *p); -+void p2p_get_hostapd_conf(struct p2p *p); -+void p2p_set_opch(struct p2p *p, char *msg, int print); -+void p2p_softap_ssid(struct p2p *p, char *msg, int print); -+void p2p_listen_ch(struct p2p *p, char *msg); -+void p2p_peer_devaddr(struct p2p *p, char *peer_devaddr); -+void p2p_peer_req_cm(struct p2p *p, char *peer_req_cm); -+void p2p_peer_info(struct p2p *p, char *peer_devaddr, char *peer_req_cm); -+void p2p_wps_cm(struct p2p *p, char *scan_addr, char *cms); -+void p2p_device_name(struct p2p *p, char *scan_addr, char *dns); -+void p2p_setDN(struct p2p *p); -+void *polling_status(void *arg); -+void *polling_client(void *arg); -+void *print_status(void *arg); -+ -+#endif //_P2P_UI_TEST_H_ -diff --git linux-5.8/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/p2p_ui_test_linux.c linux-5.8/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/p2p_ui_test_linux.c -new file mode 100644 -index 000000000..ed852848c ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/p2p_ui_test_linux.c -@@ -0,0 +1,536 @@ -+ -+#include "p2p_test.h" -+ -+char *naming_wpsinfo(int wps_info) -+{ -+ switch(wps_info) -+ { -+ case P2P_NO_WPSINFO: return ("P2P_NO_WPSINFO"); -+ case P2P_GOT_WPSINFO_PEER_DISPLAY_PIN: return ("P2P_GOT_WPSINFO_PEER_DISPLAY_PIN"); -+ case P2P_GOT_WPSINFO_SELF_DISPLAY_PIN: return ("P2P_GOT_WPSINFO_SELF_DISPLAY_PIN"); -+ case P2P_GOT_WPSINFO_PBC: return ("P2P_GOT_WPSINFO_PBC"); -+ default: return ("UI unknown failed"); -+ } -+} -+ -+char *naming_role(int role) -+{ -+ switch(role) -+ { -+ case P2P_ROLE_DISABLE: return ("P2P_ROLE_DISABLE"); -+ case P2P_ROLE_DEVICE: return ("P2P_ROLE_DEVICE"); -+ case P2P_ROLE_CLIENT: return ("P2P_ROLE_CLIENT"); -+ case P2P_ROLE_GO: return ("P2P_ROLE_GO"); -+ default: return ("UI unknown failed"); -+ } -+} -+ -+char *naming_status(int status) -+{ -+ switch(status) -+ { -+ case P2P_STATE_NONE: return ("P2P_STATE_NONE"); -+ case P2P_STATE_IDLE: return ("P2P_STATE_IDLE"); -+ case P2P_STATE_LISTEN: return ("P2P_STATE_LISTEN"); -+ case P2P_STATE_SCAN: return ("P2P_STATE_SCAN"); -+ case P2P_STATE_FIND_PHASE_LISTEN: return ("P2P_STATE_FIND_PHASE_LISTEN"); -+ case P2P_STATE_FIND_PHASE_SEARCH: return ("P2P_STATE_FIND_PHASE_SEARCH"); -+ case P2P_STATE_TX_PROVISION_DIS_REQ: return ("P2P_STATE_TX_PROVISION_DIS_REQ"); -+ case P2P_STATE_RX_PROVISION_DIS_RSP: return ("P2P_STATE_RX_PROVISION_DIS_RSP"); -+ case P2P_STATE_RX_PROVISION_DIS_REQ: return ("P2P_STATE_RX_PROVISION_DIS_REQ"); -+ case P2P_STATE_GONEGO_ING: return ("P2P_STATE_GONEGO_ING"); -+ case P2P_STATE_GONEGO_OK: return ("P2P_STATE_GONEGO_OK"); -+ case P2P_STATE_GONEGO_FAIL: return ("P2P_STATE_GONEGO_FAIL"); -+ case P2P_STATE_RECV_INVITE_REQ: return ("P2P_STATE_RECV_INVITE_REQ"); -+ case P2P_STATE_PROVISIONING_ING: return ("P2P_STATE_PROVISIONING_ING"); -+ case P2P_STATE_PROVISIONING_DONE: return ("P2P_STATE_PROVISIONING_DONE"); -+ default: return ("UI unknown failed"); -+ } -+} -+ -+char* naming_enable(int enable) -+{ -+ switch(enable) -+ { -+ case P2P_ROLE_DISABLE: return ("[Disabled]"); -+ case P2P_ROLE_DEVICE: return ("[Enable/Device]"); -+ case P2P_ROLE_CLIENT: return ("[Enable/Client]"); -+ case P2P_ROLE_GO: return ("[Enable/GO]"); -+ default: return ("UI unknown failed"); -+ } -+} -+ -+void ui_screen(struct p2p *p) -+{ -+ -+ system("clear"); -+ printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); -+ printf("****************************************************************************************************\n"); -+ printf("* P2P UI TEST v0.5 *\n"); -+ printf("****************************************************************************************************\n"); -+ printf("* Enable: %-89s*\n", naming_enable(p->enable)); -+ printf("* Intent: %2d *\n", p->intent); -+ printf("* Status: %-89s*\n", naming_status(p->status)); -+ printf("* Role: %-91s*\n", naming_role(p->role)); -+ printf("* WPS method: %-85s*\n", naming_wpsinfo(p->wps_info)); -+ printf("* PIN code: %08d *\n", p->pin); -+ -+ printf("* Device name: %-84s*\n", p->dev_name); -+ printf("* Peer device address: %-76s*\n", p->peer_devaddr); -+ printf("* Peer interface address: %-73s*\n", p->peer_ifaddr); -+ -+ printf("* *\n"); -+ printf("* e) Wi-Fi Direct Enable/Disable *\n"); -+ printf("* i) Intent ( The degree to be Group Owner/SoftAP ) *\n"); -+ printf("* a) Scan Wi-Fi Direct devices *\n"); -+ printf("* m) Peer device address you want to test *\n"); -+ printf("* p) Provision discovery *\n"); -+ printf("* c) Input PIN codes *\n"); -+ printf("* w) WPS method *\n"); -+ printf("* n) Group owner negotiation *\n"); -+ printf("* x) Start wpa_supplicant/hostapd *\n"); -+ printf("* h) Set operation channel | t) Set SoftAP ssid *\n"); -+ printf("* r) Get Current P2P Role | s) Get Current P2P Status *\n"); -+ printf("* d) Set device name | l) Set Listen channel *\n"); -+ printf("* f) Reflash Current State | q) Quit *\n"); -+ printf("****************************************************************************************************\n"); -+ -+ -+ if(p->p2p_get==0) -+ { -+ printf("* *\n"); -+ } -+ else if(p->p2p_get==1) -+ { -+ printf("*%-98s*\n", p->print_line); -+ } -+ -+ printf("****************************************************************************************************\n"); -+ -+ if( ( p->show_scan_result == 1 ) && ( p->have_p2p_dev == 1 ) ) -+ //if( (p->have_p2p_dev == 1) && (p->enable >= P2P_ROLE_DEVICE) && ( p->wpsing == 0 ) && (p->status >= P2P_STATE_LISTEN && p->status <= P2P_STATE_FIND_PHASE_SEARCH) ) -+ { -+ scan_result(p); -+ } -+ else -+ { -+ int i=0; -+ for(i = 0; i < SCAN_POOL_NO + 1; i++ ) -+ printf("* *\n"); -+ } -+ -+ printf("****************************************************************************************************\n"); -+ -+ p->show_scan_result = 0; -+} -+ -+void init_p2p(struct p2p *p) -+{ -+ strcpy( p->ifname, "wlan0" ); -+ p->enable = P2P_ROLE_DISABLE; -+ p->res = 1; -+ p->res_go = 1; -+ p->status = P2P_STATE_NONE; -+ p->intent = 1; -+ p->wps_info = 0; -+ p->wpsing = 0; -+ p->pin = 12345670; -+ p->role = P2P_ROLE_DISABLE; -+ p->listen_ch = 11; -+ strcpy( p->peer_devaddr, "00:00:00:00:00:00" ); -+ p->p2p_get = 0; -+ memset( p->print_line, 0x00, CMD_SZ); -+ p->have_p2p_dev = 0; -+ p->count_line = 0; -+ strcpy( p->peer_ifaddr, "00:00:00:00:00:00" ); -+ memset( p->cmd, 0x00, CMD_SZ); -+ p->wpa_open=0; -+ p->ap_open=0; -+ strcpy(p->ok_msg, "WiFi Direct handshake done" ); -+ strcpy(p->redo_msg, "Re-do GO handshake" ); -+ strcpy(p->fail_msg, "GO handshake unsuccessful" ); -+ strcpy(p->nego_msg, "Start P2P negotiation" ); -+ strcpy(p->wpa_conf, "./wpa_0_8.conf" ); -+ strcpy(p->wpa_path, "./wpa_supplicant" ); -+ strcpy(p->wpacli_path, "./wpa_cli" ); -+ strcpy(p->ap_conf, "./p2p_hostapd.conf" ); -+ strcpy(p->ap_path, "./hostapd" ); -+ strcpy(p->apcli_path, "./hostapd_cli" ); -+ strcpy(p->scan_msg, "Device haven't enable p2p functionalities" ); -+ -+} -+ -+void rename_intf(struct p2p *p) -+{ -+ FILE *pfin = NULL; -+ FILE *pfout = NULL; -+ -+ pfin = fopen( p->ap_conf, "r" ); -+ pfout = fopen( "./p2p_hostapd_temp.conf", "w" ); -+ -+ if ( pfin ) -+ { -+ while( !feof( pfin ) ){ -+ memset(p->parse, 0x00, CMD_SZ); -+ fgets(p->parse, CMD_SZ, pfin); -+ -+ if(strncmp(p->parse, "interface=", 10) == 0) -+ { -+ memset(p->parse, 0x00, CMD_SZ); -+ sprintf( p->parse, "interface=%s\n", p->ifname ); -+ fputs( p->parse, pfout ); -+ } -+ else -+ fputs(p->parse, pfout); -+ } -+ } -+ -+ fclose( pfout ); -+ -+ system( "rm -rf ./p2p_hostapd.conf" ); -+ system( "mv ./p2p_hostapd_temp.conf ./p2p_hostapd.conf" ); -+ -+ return; -+} -+ -+ -+//int main() -+int main(int argc, char **argv) -+{ -+ char peerifa[40] = { 0x00 }; -+ char scan[CMD_SZ]; -+ struct p2p p2pstruct; -+ struct p2p *p=NULL; -+ -+ p = &p2pstruct; -+ if( p != NULL) -+ { -+ memset(p, 0x00, sizeof(struct p2p)); -+ init_p2p(p); -+ } -+ -+ strcpy(p->ifname, argv[1] ); -+ -+ /* Disable P2P functionalities at first*/ -+ p->enable=P2P_ROLE_DISABLE; -+ p2p_enable(p); -+ p2p_get_hostapd_conf(p); -+ usleep(50000); -+ -+ rename_intf(p); -+ -+ do -+ { -+ ui_screen(p); -+ -+ printf("*insert cmd:"); -+ memset( scan, 0x00, CMD_SZ ); -+ scanf("%s", scan); -+ -+ if( p->thread_trigger == THREAD_NONE ) //Active mode for user interface -+ { -+ -+ if( strncmp(scan, "e", 1) == 0 ) //Enable -+ { -+ p->show_scan_result = 1; -+ ui_screen(p); -+ printf("Please insert enable mode;[0]Disable, [1]Device, [2]Client, [3]GO:"); -+ scanf("%d",&p->enable); -+ -+ p2p_enable(p); -+ p->show_scan_result = 1; -+ } -+ else if( strncmp(scan, "a", 1) == 0 ) // Scan P2P device -+ { -+ p2p_scan(p); -+ p->show_scan_result = 1; -+ } -+ else if( strncmp(scan, "d", 1) == 0 ) // Set device name -+ { -+ p->p2p_get = 0; -+ printf("Please insert device name :"); -+ scanf("\n%[^\n]", p->dev_name); -+ p2p_setDN(p); -+ p->show_scan_result = 1; -+ } -+ else if( strncmp(scan, "i", 1) == 0 ) // Intent -+ { -+ p->show_scan_result = 1; -+ ui_screen(p); -+ printf("Please insert intent from [0~15(must be softap)] :"); -+ scanf("%d",&p->intent); -+ p2p_intent(p); -+ p->show_scan_result = 1; -+ } -+ else if( strncmp(scan, "w", 1) == 0 ) // WPS_info -+ { -+ p->show_scan_result = 1; -+ ui_screen(p); -+ printf("Please insert WPS method\n"); -+ printf("[0]None, [1]Peer Display PIN, [2]Self Display Pin, [3]PBC :"); -+ scanf("%d",&p->wps_info); -+ p2p_wpsinfo(p); -+ p->show_scan_result = 1; -+ } -+ else if( strncmp(scan, "c", 1) == 0 ) // PIN_code -+ { -+ char ins_no[CMD_SZ], ins_no_again[CMD_SZ]; -+ memset(ins_no, 0x00, CMD_SZ); -+ strcpy(ins_no, "Please insert 8-digit number, eg:12345670 :" ); -+ memset(ins_no_again, 0x00, CMD_SZ); -+ strcpy(ins_no_again, "Invalid number, insert again, eg:12345670 :" ); -+ -+ p2p_pincode(p, ins_no, ins_no_again); -+ p->show_scan_result = 1; -+ } -+ else if( strncmp(scan, "m", 1) == 0 ) // Set peer device address -+ { -+ p->show_scan_result = 1; -+ ui_screen(p); -+ printf("Please insert number in scan list:"); -+ p2p_devaddr(p); -+ p->show_scan_result = 1; -+ } -+ else if( strncmp(scan, "r", 1) == 0 ) // Get role -+ { -+ p2p_role(p,1); -+ p->show_scan_result = 1; -+ } -+ else if( strncmp(scan, "s", 1) == 0 ) // Get status -+ { -+ p2p_status(p, 1); -+ p->show_scan_result = 1; -+ } -+ else if( strncmp(scan, "p", 1) == 0 ) // Provision discovery -+ { -+ char msg[CMD_SZ]; -+ memset( msg, 0x00, CMD_SZ ); -+ char dis_msg[CMD_SZ]; -+ memset( dis_msg, 0x00, CMD_SZ ); -+ char label_msg[CMD_SZ]; -+ memset( label_msg, 0x00, CMD_SZ ); -+ -+ -+ if(strncmp(p->peer_devaddr, "00:00:00:00:00:00", 17) == 0) -+ { -+ strcpy( msg, "Please insert peer P2P device at first" ); -+ -+ p2p_prov_disc_no_addr(p, msg); -+ p->show_scan_result = 1; -+ } -+ else -+ { -+ strcpy( msg, "Please insert WPS configuration method ;[0]display, [1]keypad, [2]pbc, [3]label:\n" ); -+ strcpy( dis_msg, "Please insert PIN code displays on peer device screen:" ); -+ strcpy( label_msg, "Please insert PIN code displays on peer label:" ); -+ -+ p2p_prov_disc(p, msg, dis_msg, label_msg); -+ } -+ } -+ else if( strncmp(scan, "n", 1) == 0 ) // Set negotiation -+ { -+ p2p_set_nego(p); -+ } -+ else if( strncmp(scan, "f", 1) == 0 ) // Reflash current state -+ { -+ p->show_scan_result = 1; -+ p2p_status(p, 0); -+ p2p_role(p, 0); -+ p2p_ifaddr(p); -+ -+ if( p->status == P2P_STATE_RX_PROVISION_DIS_REQ ) -+ { -+ char peer_devaddr[18]; -+ char peer_req_cm[4]; -+ -+ memset( peer_devaddr, 0x00, 18); -+ memset( peer_req_cm, 0x00, 4); -+ -+ p2p_peer_devaddr(p, peer_devaddr); -+ p2p_peer_req_cm(p, peer_req_cm); -+ p2p_peer_info(p, p->peer_devaddr, peer_req_cm); -+ } -+#ifndef P2P_AUTO -+ else -+ { -+ if( p->role == P2P_ROLE_CLIENT ) -+ { -+ p2p_client_mode(p); -+ } -+ else if( p->role == P2P_ROLE_GO ) -+ { -+ p2p_go_mode(p); -+ } -+ } -+#endif //P2P_AUTO -+ -+ } -+ else if( strncmp(scan, "x", 1) == 0 ) // Start wpa_supplicant/hostapd -+ { -+ if( p->role == P2P_ROLE_CLIENT ) -+ { -+ p2p_client_mode(p); -+ } -+ else if( p->role == P2P_ROLE_GO ) -+ { -+ p2p_go_mode(p); -+ } -+ } -+ else if( strncmp(scan, "h", 1) == 0 ) // Set operation channel -+ { -+ char msg[CMD_SZ]; -+ memset( msg, 0x00, CMD_SZ ); -+ strcpy( msg, "Please insert desired operation channel:" ); -+ -+ p2p_set_opch(p, msg, 1); -+ p->show_scan_result = 1; -+ } -+ else if( strncmp(scan, "t", 1) == 0 ) // Set SoftAP ssid -+ { -+ char msg[CMD_SZ]; -+ memset( msg, 0x00, CMD_SZ ); -+ strcpy( msg, "Please insert desired SoftAP ssid:" ); -+ -+ p2p_softap_ssid(p, msg, 1); -+ p->show_scan_result = 1; -+ } -+ else if( strncmp(scan, "l", 1) == 0 ) // Set Listen channel -+ { -+ char msg[CMD_SZ]; -+ memset( msg, 0x00, CMD_SZ ); -+ strcpy( msg, "Please insert desired Listen channel, only ch.1.6.11 are available:" ); -+ -+ p2p_listen_ch(p, msg); -+ p->show_scan_result = 1; -+ } -+ else if( strncmp(scan, "q", 1) == 0 ) // Quit -+ { -+ if( p->res == 0 ) -+ p->res = 1; -+ if( p->res_go == 0 ) -+ p->res_go = 1; -+ break; -+ } -+ else // Insert wrong commamd -+ { -+ p->p2p_get=1; -+ p->show_scan_result = 1; -+ memset( p->print_line, 0x00, CMD_SZ ); -+ sprintf( p->print_line, " BAD argument"); -+ } -+ -+ } -+ else if( p->thread_trigger == THREAD_DEVICE ) //Passive mode for user interface -+ { -+ -+ p->thread_trigger = THREAD_NONE ; -+ -+ if( strncmp(scan, "b", 1) == 0 ) -+ { -+ p->wps_info=3; -+ p2p_wpsinfo(p); -+ -+ p2p_status(p, 0); -+ -+ if(p->status != P2P_STATE_GONEGO_OK) -+ { -+ p2p_set_nego(p); -+ } -+ else -+ { -+ p2p_role(p,0); -+ -+ if( p->role == P2P_ROLE_CLIENT ) -+ { -+ p2p_client_mode(p); -+ } -+ else if( p->role == P2P_ROLE_GO ) -+ { -+ p2p_go_mode(p); -+ } -+ } -+ } -+ else if( strncmp(scan, "c", 1) == 0 ) -+ { -+ p->wps_info=2; -+ p2p_wpsinfo(p); -+ -+ p2p_status(p, 0); -+ -+ if(p->status != P2P_STATE_GONEGO_OK) -+ { -+ p2p_set_nego(p); -+ } -+ else -+ { -+ p2p_role(p,0); -+ p2p_ifaddr(p); -+ -+ if( p->role == P2P_ROLE_CLIENT ) -+ { -+ p2p_client_mode(p); -+ } -+ else if( p->role == P2P_ROLE_GO ) -+ { -+ p2p_go_mode(p); -+ } -+ } -+ } -+ else if( ('0' <= *scan ) && ( *scan <= '9') ) -+ { -+ printf("In passive pin code\n"); -+ -+ p->pin = atoi(scan); -+ -+ p->wps_info=1; -+ p2p_wpsinfo(p); -+ -+ p2p_set_nego(p); -+ } -+ } -+ else if( p->thread_trigger == THREAD_GO ) //Passive mode for user interface -+ { -+ -+ p->thread_trigger = THREAD_NONE ; -+ -+ if( strncmp(scan, "b", 1) == 0 ) -+ { -+ p->wps_info=3; -+ p2p_wpsinfo(p); -+ -+ } -+ else if( strncmp(scan, "c", 1) == 0 ) -+ { -+ p->wps_info=2; -+ p2p_wpsinfo(p); -+ } -+ else if( ('0' <= *scan ) && ( *scan <= '9') ) -+ { -+ printf("In passive pin code\n"); -+ -+ p->pin = atoi(scan); -+ -+ p->wps_info=1; -+ p2p_wpsinfo(p); -+ } -+ -+ p2p_go_mode(p); -+ -+ } -+ } -+ while( 1 ); -+ -+ /* Disable P2P functionalities when exits*/ -+ p->enable= -1 ; -+ p2p_enable(p); -+ -+ system( "rm -f ./supp_status.txt" ); -+ system( "rm -f ./temp.txt" ); -+ system( "rm -f ./scan.txt" ); -+ system( "rm -f ./peer.txt" ); -+ system( "rm -f ./status.txt" ); -+ system( "rm -f ./cm.txt" ); -+ -+ return 0; -+ -+} -diff --git linux-5.8/3rdparty/rtl8812au/tools/analyze_suspend.py linux-5.8/3rdparty/rtl8812au/tools/analyze_suspend.py -new file mode 100755 -index 000000000..e5b7c3824 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/tools/analyze_suspend.py +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/tools/analyze_suspend.py linux-5.11.4-rtl8812au/3rdparty/rtl8812au/tools/analyze_suspend.py +--- linux-5.11.4/3rdparty/rtl8812au/tools/analyze_suspend.py 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/tools/analyze_suspend.py 2021-03-07 18:16:17.101958275 +0200 @@ -0,0 +1,3441 @@ -+#!/usr/bin/python3 ++#!/usr/bin/python +# +# Tool for analyzing suspend/resume timing +# Copyright (c) 2013, Intel Corporation. @@ -470843,11 +467350,9 @@ index 000000000..e5b7c3824 + else: + # run the test in the current directory + runTest(".") -diff --git linux-5.8/3rdparty/rtl8812au/tools/checkpatch.pl linux-5.8/3rdparty/rtl8812au/tools/checkpatch.pl -new file mode 100755 -index 000000000..93a7edfe0 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/tools/checkpatch.pl +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/tools/checkpatch.pl linux-5.11.4-rtl8812au/3rdparty/rtl8812au/tools/checkpatch.pl +--- linux-5.11.4/3rdparty/rtl8812au/tools/checkpatch.pl 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/tools/checkpatch.pl 2021-03-07 18:16:17.101958275 +0200 @@ -0,0 +1,6759 @@ +#!/usr/bin/env perl +# SPDX-License-Identifier: GPL-2.0 @@ -477608,11 +474113,9 @@ index 000000000..93a7edfe0 + } + return $clean; +} -diff --git linux-5.8/3rdparty/rtl8812au/tools/const_structs.checkpatch linux-5.8/3rdparty/rtl8812au/tools/const_structs.checkpatch -new file mode 100644 -index 000000000..ac5f12671 ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/tools/const_structs.checkpatch +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/tools/const_structs.checkpatch linux-5.11.4-rtl8812au/3rdparty/rtl8812au/tools/const_structs.checkpatch +--- linux-5.11.4/3rdparty/rtl8812au/tools/const_structs.checkpatch 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/tools/const_structs.checkpatch 2021-03-07 18:16:17.101958275 +0200 @@ -0,0 +1,64 @@ +acpi_dock_ops +address_space_operations @@ -477678,11 +474181,9 @@ index 000000000..ac5f12671 +vm_operations_struct +wacom_features +wd_ops -diff --git linux-5.8/3rdparty/rtl8812au/tools/install-and-sign-ubuntu.sh linux-5.8/3rdparty/rtl8812au/tools/install-and-sign-ubuntu.sh -new file mode 100755 -index 000000000..dc3b0266b ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/tools/install-and-sign-ubuntu.sh +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/tools/install-and-sign-ubuntu.sh linux-5.11.4-rtl8812au/3rdparty/rtl8812au/tools/install-and-sign-ubuntu.sh +--- linux-5.11.4/3rdparty/rtl8812au/tools/install-and-sign-ubuntu.sh 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/tools/install-and-sign-ubuntu.sh 2021-03-07 18:16:17.101958275 +0200 @@ -0,0 +1,57 @@ +#!/bin/bash + @@ -477741,15 +474242,33 @@ index 000000000..dc3b0266b +else + modprobe 88XXau +fi -diff --git linux-5.8/3rdparty/rtl8812au/tools/rtwpriv.zip linux-5.8/3rdparty/rtl8812au/tools/rtwpriv.zip -new file mode 100644 -index 000000000..856f706f6 -Binary files /dev/null and linux-5.8/3rdparty/rtl8812au/tools/rtwpriv.zip differ -diff --git linux-5.8/3rdparty/rtl8812au/tools/spelling.txt linux-5.8/3rdparty/rtl8812au/tools/spelling.txt -new file mode 100644 -index 000000000..de75b9fea ---- /dev/null -+++ linux-5.8/3rdparty/rtl8812au/tools/spelling.txt +De binära filerna linux-5.11.4/3rdparty/rtl8812au/tools/RtkMpTool.apk och linux-5.11.4-rtl8812au/3rdparty/rtl8812au/tools/RtkMpTool.apk skiljer +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/tools/RtkMpTool-ReadMe.txt linux-5.11.4-rtl8812au/3rdparty/rtl8812au/tools/RtkMpTool-ReadMe.txt +--- linux-5.11.4/3rdparty/rtl8812au/tools/RtkMpTool-ReadMe.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/tools/RtkMpTool-ReadMe.txt 2021-03-07 18:16:17.098958132 +0200 +@@ -0,0 +1,18 @@ ++RtkMpTool.apk need to use "rtwpriv", ++please frist to prepare build the rtwpriv and push to Android system. ++ ++Installation steps: ++1. adb push rtwpriv /system/bin/ ++2. adb shell chmod 755 /system/bin/rtwpriv ++3. adb push 8xxx.ko "your system wlan default module's folder"\wlan.ko (etc. /system/lib/modules/wlan.ko) ++4. adb install RtkMpTool.apk ++or adb install RtkWiFiTest.apk ++5. a.After execute the MP tool.Frist to use the "adb shell rtwpriv wlan0 mp_start" to check this driver can support mp command. ++ b.The "mp_start" command must to be no show any error message. ++ ++P.S. ++1. RtkMpTool.apk only supports the MP test functions. ++After installed, you will see a "Realtek MP Tool" App on the phone. ++ ++2. RtkWiFiTest.apk supports both MP test and CTA test functions. ++After installed, you will see a "WiFi Test" App on the phone. +De binära filerna linux-5.11.4/3rdparty/rtl8812au/tools/rtwpriv.zip och linux-5.11.4-rtl8812au/3rdparty/rtl8812au/tools/rtwpriv.zip skiljer +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/tools/spelling.txt linux-5.11.4-rtl8812au/3rdparty/rtl8812au/tools/spelling.txt +--- linux-5.11.4/3rdparty/rtl8812au/tools/spelling.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/tools/spelling.txt 2021-03-07 18:16:17.101958275 +0200 @@ -0,0 +1,1447 @@ +# Originally from Debian's Lintian tool. Various false positives have been +# removed, and various additions have been made as they've been discovered @@ -479198,3 +475717,2216 @@ index 000000000..de75b9fea +wtih||with +zombe||zombie +zomebie||zombie +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/Android.mk linux-5.11.4-rtl8812au/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/Android.mk +--- linux-5.11.4/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/Android.mk 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/Android.mk 2021-03-07 18:16:17.099958180 +0200 +@@ -0,0 +1,11 @@ ++ifneq ($(TARGET_SIMULATOR),true) ++LOCAL_PATH:= $(call my-dir) ++ ++include $(CLEAR_VARS) ++LOCAL_SRC_FILES += p2p_api_test_linux.c p2p_ui_test_linux.c ++LOCAL_SHARED_LIBRARIES := libc libcutils ++LOCAL_MODULE = P2P_UI ++LOCAL_MODULE_TAGS := optional ++include $(BUILD_EXECUTABLE) ++ ++endif +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/install.sh linux-5.11.4-rtl8812au/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/install.sh +--- linux-5.11.4/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/install.sh 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/install.sh 2021-03-07 18:16:17.100958228 +0200 +@@ -0,0 +1,100 @@ ++ ++wpa_supplicant_hostapd=`ls -1 ../wpa_supplicant_hostapd/wpa_supplicant_hostapd-0.8_*` ++echo $wpa_supplicant_hostapd ++ ++ ++if [ -e $wpa_supplicant_hostapd ]; then ++ echo "Checking wpa_supplicant_hostatpd" ++else ++ echo "wpa_supplicant_hostapd doesn'tt exist in corresponding folder" ++ exit ++fi ++ ++if [ -e ../wpa_supplicant_hostapd/p2p_hostapd.conf ]; then ++ echo "Checking p2p_hostapd.conf" ++else ++ echo "p2p_hostapd.conf doesn't exist in corresponding folder" ++ exit ++fi ++ ++if [ -e ../wpa_supplicant_hostapd/wpa_0_8.conf ]; then ++ echo "Checking wpa_0_8.conf" ++else ++ echo "wpa_0_8.conf doesn't exist in corresponding folder" ++ exit ++fi ++ ++#cp ../wpa_supplicant_hostapd/wpa_supplicant_hostapd-0.8_rtw_20111118.zip ./ ++cp $wpa_supplicant_hostapd ./ ++wpa_supplicant_hostapd=`ls -1 ./wpa_supplicant_hostapd-0.8_*` ++echo " "$wpa_supplicant_hostapd ++unzip $wpa_supplicant_hostapd ++ ++cd wpa_supplicant_hostapd-0.8 ++cd wpa_supplicant ++make clean all ++ ++cd .. ++cd hostapd ++make clean all ++ ++cd .. ++cd .. ++ ++cp ../wpa_supplicant_hostapd/p2p_hostapd.conf ./ ++cp ../wpa_supplicant_hostapd/wpa_0_8.conf ./ ++cp ./wpa_supplicant_hostapd-0.8/hostapd/hostapd ./ ++cp ./wpa_supplicant_hostapd-0.8/hostapd/hostapd_cli ./ ++cp ./wpa_supplicant_hostapd-0.8/wpa_supplicant/wpa_supplicant ./ ++cp ./wpa_supplicant_hostapd-0.8/wpa_supplicant/wpa_cli ./ ++ ++rm -rf wpa_supplicant_hostapd-0.8 ++rm -rf $wpa_supplicant_hostapd ++ ++gcc -o P2P_UI ./p2p_api_test_linux.c ./p2p_ui_test_linux.c -lpthread ++ ++if [ ! -e ./p2p_hostapd.conf ]; then ++ echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" ++ echo "Doesn't have p2p_hostapd.conf" ++ result="fail" ++fi ++ ++if [ ! -e ./wpa_0_8.conf ]; then ++ echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" ++ echo "Doesn't have wpa_0_8.conf" ++ result="fail" ++fi ++ ++if [ ! -e ./hostapd ]; then ++ echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" ++ echo "Doesn't have hostapd" ++ result="fail" ++fi ++ ++if [ ! -e ./wpa_supplicant ]; then ++ echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" ++ echo "Doesn't have hostapd_cli" ++ result="fail" ++fi ++ ++if [ ! -e ./wpa_cli ]; then ++ echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" ++ echo "Doesn't have p2p_hostapd.conf" ++ result="fail" ++fi ++ ++if [ ! -e ./P2P_UI ]; then ++ echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" ++ echo "Doesn't have P2P_UI" ++ result="fail" ++fi ++ ++if [ "$result" == "fail" ]; then ++ echo "WiFi_Direct_User_Interface install unsuccessful" ++ echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" ++ exit ++fi ++ ++echo "##################################################" ++echo "WiFi_Direct_User_Interface install complete!!!!!!!" ++echo "##################################################" +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/p2p_api_test_linux.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/p2p_api_test_linux.c +--- linux-5.11.4/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/p2p_api_test_linux.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/p2p_api_test_linux.c 2021-03-07 18:16:17.100958228 +0200 +@@ -0,0 +1,1377 @@ ++ ++#include "p2p_test.h" ++ ++unsigned int wps_pin_checksum(unsigned int pin) ++{ ++ unsigned int accum = 0; ++ while( pin ) ++ { ++ accum += pin % 10; ++ pin /= 10; ++ accum += 3 * (pin % 10); ++ pin /= 10; ++ } ++ return( accum % 10 ); ++} ++ ++char lower(char s) ++{ ++ if(('A' <= s) && (s <= 'Z')) ++ return ( s = 'a' + (s - 'A') ); ++ return s; ++} ++ ++int p2p_check_success(struct p2p *p) ++{ ++ int ret = 0; ++ ++ if( p->status == P2P_STATE_GONEGO_OK ) ++ ret = 1; ++ ++ return ret; ++} ++ ++int read_all_sta(struct p2p *p) ++{ ++ int sta_count = 0; ++ FILE *pf; ++ ++ memset( p->cmd, 0x00, CMD_SZ ); ++ sprintf( p->cmd, "%s all_sta > supp_status.txt", p->apcli_path); ++ system( p->cmd ); ++ pf = fopen( "./supp_status.txt", "r" ); ++ if ( pf ) ++ { ++ while( !feof( pf ) ){ ++ memset( p->parse, 0x00, CMD_SZ ); ++ fgets( p->parse, CMD_SZ, pf ); ++ if( strncmp( p->parse, "dot11RSNAStatsSTAAddress=", 25) == 0 ) ++ { ++ sta_count++; ++ if( p->no_sta_connected == sta_count ) ++ return _TRUE; ++ } ++ } ++ ++ fclose( pf ); ++ } ++ ++ return _FALSE; ++} ++ ++void do_wps(struct p2p *p) ++{ ++ FILE *pf = NULL; ++ int ret = _FALSE, parsing_ok = _FALSE; ++ ++ do ++ { ++ memset( p->cmd, 0x00, CMD_SZ ); ++ if( p->ap_open == _TRUE ) ++ { ++ if(p->wps_info==1 || p->wps_info==2) ++ sprintf( p->cmd, "%s wps_pin any %d > supp_status.txt", p->apcli_path, p->pin); ++ else if(p->wps_info==3) ++ sprintf( p->cmd, "%s wps_pbc any > supp_status.txt", p->apcli_path); ++ } ++ else if(p->wpa_open == _TRUE) ++ { ++ if(p->connect_go==1) ++ { ++ if(p->wps_info==1 || p->wps_info==2) ++ sprintf( p->cmd, "%s wps_pin %s %d > supp_status.txt ", p->wpacli_path, p->peer_devaddr, p->pin); ++ else if(p->wps_info==3) ++ sprintf( p->cmd, "%s wps_pbc %s > supp_status.txt ", p->wpacli_path, p->peer_devaddr); ++ } ++ else if( strncmp(p->peer_ifaddr, "00:00:00:00:00:00", 17)==0 ) ++ { ++ if(p->wps_info==1 || p->wps_info==2) ++ sprintf( p->cmd, "%s wps_pin any %d > supp_status.txt ", p->wpacli_path, p->pin); ++ else if(p->wps_info==3) ++ sprintf( p->cmd, "%s wps_pbc any > supp_status.txt ", p->wpacli_path); ++ } ++ else ++ { ++ if(p->wps_info==1 || p->wps_info==2) ++ sprintf( p->cmd, "%s wps_pin %s %d > supp_status.txt ", p->wpacli_path, p->peer_ifaddr, p->pin); ++ else if(p->wps_info==3) ++ sprintf( p->cmd, "%s wps_pbc %s > supp_status.txt ", p->wpacli_path, p->peer_ifaddr); ++ } ++ } ++ system( p->cmd ); ++ ++ pf = fopen( "./supp_status.txt", "r" ); ++ if ( pf ) ++ { ++ while( !feof( pf ) ){ ++ memset(p->parse, 0x00, CMD_SZ); ++ fgets(p->parse, CMD_SZ, pf); ++ ++ if(p->ap_open == _TRUE) ++ { ++ if( (p->wps_info==1 || p->wps_info==2) && (strncmp(p->parse, "", 2) == 0) ) ++ parsing_ok = _TRUE; ++ else if( (p->wps_info==3) && (strncmp(p->parse, "OK", 2) == 0) ) ++ parsing_ok = _TRUE; ++ } ++ else if(p->wpa_open == _TRUE) ++ { ++ if( (p->wps_info==1 || p->wps_info==2) && (strncmp(p->parse, "Selected", 8) == 0) ) ++ parsing_ok = _TRUE; ++ else if( (p->wps_info==3) && (strncmp(p->parse, "OK", 2) == 0) ) ++ parsing_ok = _TRUE; ++ } ++ ++ if( parsing_ok == _TRUE ) ++ { ++ ret = _TRUE; ++ p->wpsing = _TRUE; ++ } ++ } ++ ++ fclose( pf ); ++ } ++ ++ if( ret == 0 ) ++ usleep( HOSTAPD_INIT_TIME ); ++ } ++ while( ret == 0 ); ++} ++ ++void p2p_enable(struct p2p *p) ++{ ++ p->have_p2p_dev = 0; ++ p->connect_go = 0; ++ ++ if(p->enable == -1 ) ++ { ++ if(p->wpa_open == _TRUE){ ++ p->wpa_open = _FALSE; ++ system("killall wpa_supplicant"); ++#ifdef DHCP ++ system("killall dhclient"); ++#endif ++ } ++ if(p->ap_open == _TRUE){ ++ p->ap_open = _FALSE; ++ system("killall hostapd"); ++#ifdef DHCP ++ system("killall dhcpd"); ++#endif ++ } ++ ++ memset( p->cmd, 0x00, CMD_SZ ); ++ sprintf( p->cmd, "iwpriv %s p2p_set enable=0", p->ifname); ++ system( p->cmd ); ++ ++ return; ++ } ++ ++ p->p2p_get=0; ++ memset( p->cmd, 0x00, CMD_SZ ); ++ sprintf( p->cmd, "iwpriv %s p2p_set enable=%d", p->ifname, p->enable); ++ system( p->cmd ); ++ ++ if( p->enable == P2P_ROLE_DISABLE ) ++ { ++ p->wps_info = 0; ++ p->pin = 12345670; ++ ++ p2p_status(p, 0); ++ p2p_role(p, 0); ++ ++ if(p->res == 0) ++ { ++ p->res = 1; ++ } ++ ++ if(p->res_go == 0) ++ { ++ p->res_go = 1; ++ } ++ ++ p->wpa_open = _FALSE; ++ system("killall wpa_supplicant"); ++#ifdef DHCP ++ system("killall dhclient"); ++#endif ++ system("clear"); ++ p->ap_open = _FALSE; ++ system("killall hostapd"); ++#ifdef DHCP ++ system("killall dhcpd"); ++#endif ++ system("clear"); ++ ++ } ++ else if( p->enable == P2P_ROLE_DEVICE ) ++ { ++ char msg[5] = "NULL"; ++ ++#ifdef P2P_AUTO ++ p->res = pthread_create(&p->pthread, NULL, &polling_status, (void *)p); ++#endif ++ ++ if( p->res !=0 ) ++ { ++ p->p2p_get=1; ++ memset( p->print_line, 0x00, CMD_SZ ); ++ sprintf( p->print_line, "Thread creation failed" ); ++ } ++ ++ if(p->wpa_open == _TRUE){ ++ p->wpa_open = _FALSE; ++ system("killall wpa_supplicant"); ++#ifdef DHCP ++ system("killall dhclient"); ++#endif ++ } ++ if(p->ap_open == _TRUE){ ++ p->ap_open = _FALSE; ++ system("killall hostapd"); ++#ifdef DHCP ++ system("killall dhcpd"); ++#endif ++ } ++ ++ p->intent = 1; ++ p2p_intent(p); ++ ++ p2p_set_opch(p, NULL, 0); ++ usleep(50000); ++ p2p_softap_ssid(p, NULL, 0); ++ ++ p2p_setDN(p); ++ p2p_role(p, 0); ++ ++ p2p_scan(p); ++ ++ } ++ else if( p->enable == P2P_ROLE_CLIENT ) ++ { ++ if(p->ap_open == _TRUE){ ++ p->ap_open = _FALSE; ++ system("killall hostapd"); ++#ifdef DHCP ++ system("killall dhcpd"); ++#endif ++ } ++ ++ p2p_status(p, 0); ++ p2p_role(p, 0); ++ p2p_intent(p); ++ } ++ else if( p->enable == P2P_ROLE_GO ) ++ { ++ if(p->wpa_open == _TRUE){ ++ p->wpa_open = _FALSE; ++ system("killall wpa_supplicant"); ++#ifdef DHCP ++ system("killall dhclient"); ++#endif ++ } ++ ++ p2p_status(p, 0); ++ p2p_role(p, 0); ++ p2p_intent(p); ++ ++ p2p_set_opch(p, NULL, 0); ++ usleep(50000); ++ p2p_softap_ssid(p, NULL, 0); ++ ++ p2p_setDN(p); ++ ++ if(p->ap_open != _TRUE) ++ { ++ memset( p->cmd, 0x00, CMD_SZ ); ++ sprintf( p->cmd, "%s -B %s > temp.txt",p->ap_path, p->ap_conf); ++ system( p->cmd ); ++ ++ p->ap_open = _TRUE; ++ } ++ ++#ifdef P2P_AUTO ++ p->res_go = pthread_create(&p->pthread_go, NULL, &polling_client, (void *)p); ++#endif ++ ++ if( p->res_go != 0 ) ++ { ++ p->p2p_get=1; ++ memset( p->print_line, 0x00, CMD_SZ ); ++ sprintf( p->print_line, "Thread creation failed" ); ++ } ++ ++ } ++ ++} ++ ++void p2p_scan(struct p2p *p) ++{ ++ p->p2p_get=0; ++ if( p->enable >= P2P_ROLE_DEVICE ) ++ { ++ p->have_p2p_dev=1; ++ memset( p->cmd, 0x00, CMD_SZ ); ++ sprintf( p->cmd, "iwlist %s scan > scan.txt", p->ifname ); ++ system( p->cmd ); ++ ++ p2p_status(p, 0); ++ ++ } ++ else ++ { ++ p->p2p_get=1; ++ memset( p->print_line, 0x00, CMD_SZ ); ++ sprintf( p->print_line, "%s", p->scan_msg ); ++ } ++} ++ ++void scan_result(struct p2p *p) ++{ ++ FILE *pf=NULL; ++ int no_dev=0; ++ char cms[30] = { 0x00 }; ++ char dns[SSID_SZ] = { 0x00 }; ++ char parse[100] = { 0x00 }; ++ struct scan *pscan_pool; ++ ++ pf = fopen( "./scan.txt", "r" ); ++ if ( pf ) ++ { ++ p->count_line=0; ++ while( (!feof( pf )) && (no_dev < SCAN_POOL_NO)) ++ { ++ memset( parse, 0x00, CMD_SZ ); ++ fgets( parse, CMD_SZ, pf ); ++ ++ if(parse[0] == '\n' || parse[0] == '\0') ++ break; ++ if( strncmp(parse+10, "Scan completed :", 16) == 0 ) ++ { ++ printf("* NO DEVICE NAME BSSID GO CONFIG METHOD *\n"); ++ p->count_line++; ++ } ++ else if( strncmp(parse+20, "Address:", 8) == 0 ) ++ { ++ pscan_pool = &p->scan_pool[no_dev]; ++ memset( pscan_pool->addr, 0x00, sizeof(struct scan) ); ++ strncpy( pscan_pool->addr, parse+29, 17); ++ } ++ else if( strncmp(parse+20, "ESSID:", 6) == 0 ) ++ { ++ pscan_pool = &p->scan_pool[no_dev]; ++ ++ p2p_wps_cm(p, pscan_pool->addr, cms); ++ p2p_device_name(p, pscan_pool->addr, dns); ++ ++ if( strncmp(parse+26, "\"DIRECT-\"", 9) == 0 ) ++ { ++ printf("*[%02d] %-25s %s %-38s*\n",no_dev+1, dns, pscan_pool->addr, cms); ++ } ++ else ++ { ++ printf("*[%02d] %-25s %s * %-38s*\n",no_dev+1, dns, pscan_pool->addr, cms); ++ pscan_pool->go = 1; ++ } ++ p->count_line++; ++ no_dev++; ++ ++ } ++ } ++ ++ if( p->count_line < (SCAN_POOL_NO + 1) ) ++ { ++ for(p->count_line; p->count_line < SCAN_POOL_NO+1; p->count_line++ ) ++ printf("* *\n"); ++ } ++ fclose( pf ); ++ } ++ ++} ++ ++void p2p_setDN(struct p2p *p) ++{ ++ ++ memset( p->cmd, 0x00, CMD_SZ ); ++ sprintf( p->cmd, "iwpriv %s p2p_set setDN=%s", p->ifname, p->dev_name); ++ system( p->cmd ); ++} ++ ++void p2p_intent(struct p2p *p) ++{ ++ p->p2p_get=0; ++ memset( p->cmd, 0x00, CMD_SZ ); ++ sprintf( p->cmd, "iwpriv %s p2p_set intent=%d", p->ifname, p->intent); ++ system( p->cmd ); ++} ++ ++void p2p_wpsinfo(struct p2p *p) ++{ ++ p->p2p_get=0; ++ memset( p->cmd, 0x00, CMD_SZ ); ++ sprintf( p->cmd, "iwpriv %s p2p_set got_wpsinfo=%d", p->ifname, p->wps_info); ++ system( p->cmd ); ++} ++ ++void p2p_pincode(struct p2p *p, char *ins_no, char *ins_no_again) ++{ ++ int pin_check=0; ++ p->p2p_get=0; ++ p->show_scan_result = 1; ++ ui_screen(p); ++ printf("%s", ins_no); ++ scanf("%d",&pin_check); ++ while( wps_pin_checksum(pin_check) != 0 ) ++ { ++ p->show_scan_result = 1; ++ ui_screen(p); ++ printf("%s", ins_no_again); ++ scanf("%d",&pin_check); ++ } ++ p->pin = pin_check; ++} ++ ++void p2p_devaddr(struct p2p *p) ++{ ++ int c; ++ struct scan *pscan_pool; ++ ++ p->p2p_get=0; ++ ++ scanf("%d", &c); ++ pscan_pool = &p->scan_pool[c-1]; ++ strncpy(p->peer_devaddr, pscan_pool->addr, 17); ++ ++ if( pscan_pool->go == 1) ++ p->connect_go = 1; ++} ++ ++void p2p_role(struct p2p *p, int flag) ++{ ++ FILE *pf=NULL; ++ ++ memset( p->cmd, 0x00, CMD_SZ ); ++ sprintf( p->cmd, "iwpriv %s p2p_get role > status.txt", p->ifname); ++ system( p->cmd ); ++ ++ pf = fopen( "./status.txt", "r" ); ++ if ( pf ) ++ { ++ while( !feof( pf ) ){ ++ memset( p->parse, 0x00, CMD_SZ ); ++ fgets( p->parse, CMD_SZ, pf ); ++ if( strncmp( p->parse, "Role", 4) == 0 ) ++ { ++ p->role = atoi( &p->parse[ 5 ] ); ++ if(flag==1){ ++ p->p2p_get=1; ++ sprintf( p->print_line, "Role=%s", naming_role(p->role)); ++ } ++ break; ++ } ++ } ++ fclose( pf ); ++ } ++} ++ ++void p2p_status(struct p2p *p, int flag) ++{ ++ FILE *pf=NULL; ++ ++ memset( p->cmd, 0x00, CMD_SZ ); ++ sprintf( p->cmd, "iwpriv %s p2p_get status > status.txt", p->ifname); ++ system( p->cmd ); ++ ++ pf = fopen( "./status.txt", "r" ); ++ if ( pf ) ++ { ++ while( !feof( pf ) ){ ++ memset( p->parse, 0x00, CMD_SZ ); ++ fgets( p->parse, CMD_SZ, pf ); ++ if( strncmp( p->parse, "Status", 6) == 0 ) ++ { ++ p->status = atoi( &p->parse[ 7 ] ); ++ if(flag==1){ ++ p->p2p_get=1; ++ sprintf( p->print_line, "Status=%s", naming_status(p->status)); ++ } ++ break; ++ } ++ } ++ fclose( pf ); ++ } ++} ++ ++void change_hostapd_op_ch(struct p2p *p, int op_ch) ++{ ++ FILE *pfin = NULL; ++ FILE *pfout = NULL; ++ char parse[CMD_SZ] = { 0x00 }; ++ char cmd[CMD_SZ] = { 0x00 }; ++ ++ pfin = fopen( p->ap_conf, "r" ); ++ pfout = fopen( "./p2p_hostapd_temp.conf", "w" ); ++ ++ if( pfin && pfout ) ++ { ++ while( !feof( pfin ) ){ ++ memset( parse, 0x00, CMD_SZ ); ++ fgets( parse, CMD_SZ, pfin ); ++ ++ if(strncmp(parse, "channel=", 8) == 0) ++ { ++ memset(parse, 0x00, CMD_SZ); ++ sprintf( parse, "channel=%d\n", op_ch ); ++ fputs( parse, pfout ); ++ } ++ else ++ fputs(parse, pfout); ++ } ++ } ++ else ++ { ++ return; ++ } ++ ++ if( pfin != NULL ) ++ fclose( pfin ); ++ if( pfout != NULL ) ++ fclose( pfout ); ++ ++ memset( cmd, 0x00, CMD_SZ); ++ sprintf( cmd, "rm -rf %s", p->ap_conf ); ++ system( cmd ); ++ memset( cmd, 0x00, CMD_SZ); ++ sprintf( cmd, "mv ./p2p_hostapd_temp.conf %s", p->ap_conf ); ++ system( cmd ); ++ ++ return; ++} ++ ++void p2p_get_opch(struct p2p *p) ++{ ++ FILE *pf=NULL; ++ int peer_op_ch = 0; ++ ++ memset( p->cmd, 0x00, CMD_SZ ); ++ sprintf( p->cmd, "iwpriv %s p2p_get op_ch > cm.txt", p->ifname); ++ system( p->cmd ); ++ ++ pf = fopen( "./cm.txt", "r" ); ++ if ( pf ) ++ { ++ while( !feof( pf ) ){ ++ memset( p->parse, 0x00, CMD_SZ ); ++ fgets( p->parse, CMD_SZ, pf ); ++ if( strncmp( p->parse, "Op_ch", 5) == 0 ) ++ { ++ peer_op_ch = atoi( &p->parse[ 6 ] ); ++ if( peer_op_ch != p->op_ch ) ++ { ++ change_hostapd_op_ch( p, peer_op_ch ); ++ } ++ break; ++ } ++ } ++ fclose( pf ); ++ } ++} ++ ++void p2p_prov_disc_no_addr(struct p2p *p, char *msg) ++{ ++ p->p2p_get=1; ++ memset( p->print_line, 0x00, CMD_SZ ); ++ sprintf( p->print_line, "%s", msg); ++} ++ ++#ifdef P2P_AUTO ++void p2p_prov_disc(struct p2p *p, char *msg, char *dis_msg, char *label_msg) ++{ ++ int wps_cm, retry_count=0; ++ char prov[100] = { 0x00 }; ++ ++ p->p2p_get=0; ++ p->show_scan_result = 1; ++ ui_screen(p); ++ printf("%s", msg); ++ scanf("%d",&wps_cm); ++ ++ if(p->res == 0) ++ { ++ p->res = 1; ++ } ++ ++ memset( p->cmd, 0x00, CMD_SZ ); ++ if( wps_cm == 0 ) ++ sprintf( p->cmd, "iwpriv %s p2p_set prov_disc=%s_display", p->ifname, p->peer_devaddr); ++ else if( wps_cm == 1 ) ++ sprintf( p->cmd, "iwpriv %s p2p_set prov_disc=%s_keypad", p->ifname, p->peer_devaddr); ++ else if( wps_cm == 2 ) ++ sprintf( p->cmd, "iwpriv %s p2p_set prov_disc=%s_pbc", p->ifname, p->peer_devaddr); ++ else if( wps_cm == 3 ) ++ sprintf( p->cmd, "iwpriv %s p2p_set prov_disc=%s_label", p->ifname, p->peer_devaddr); ++ system( p->cmd ); ++ strcpy( prov, p->cmd ); ++ ++ usleep(500000); ++ p2p_status( p, 0 ); ++ ++ while( p->status != P2P_STATE_RX_PROVISION_DIS_RSP && retry_count < MAX_PROV_RETRY) ++ { ++ usleep( PROV_WAIT_TIME ); ++ retry_count++; ++ p2p_status( p, 0 ); ++ if( (retry_count % PROV_RETRY_INTERVAL) == 0) ++ system( prov ); ++ } ++ ++ if( p->status == P2P_STATE_RX_PROVISION_DIS_RSP ) ++ { ++ switch(wps_cm) ++ { ++ case 0: p->wps_info=1; break; ++ case 1: p->wps_info=2; break; ++ case 2: p->wps_info=3; break; ++ case 3: p->wps_info=1; break; ++ } ++ ++ if( wps_cm==1 || wps_cm==2 ) ++ { ++ p2p_wpsinfo(p); ++ ++ if(p->connect_go == 1) ++ p2p_client_mode(p); ++ else ++ p2p_set_nego(p); ++ } ++ else if( wps_cm==0 || wps_cm==3 ) ++ { ++ ui_screen(p); ++ if( wps_cm ==0 ) ++ printf("%s", dis_msg); ++ else if( wps_cm == 3 ) ++ printf("%s", label_msg); ++ scanf("%d",&p->pin); ++ ++ p2p_wpsinfo(p); ++ ++ if(p->connect_go == 1) ++ p2p_client_mode(p); ++ else ++ p2p_set_nego(p); ++ ++ } ++ } ++ else ++ { ++ p->p2p_get = 1; ++ memset( p->print_line, 0x00, CMD_SZ ); ++ sprintf( p->print_line, "Issue provision discovery fail" ); ++ ui_screen(p); ++ ++#ifdef P2P_AUTO ++ pthread_create(&p->pthread, NULL, &polling_status, (void *)p); ++#endif ++ ++ } ++ ++} ++#else ++ ++// This mode is without the following procedures: ++// 1.set config method ++// 2.start group negotiation ++// 3.start wpa_supplicant or hostapd ++void p2p_prov_disc(struct p2p *p, char *msg, char *dis_msg, char *label_msg) ++{ ++ int wps_cm; ++ p->p2p_get=0; ++ p->show_scan_result = 1; ++ ui_screen(p); ++ printf("%s", msg); ++ scanf("%d",&wps_cm); ++ memset( p->cmd, 0x00, CMD_SZ ); ++ ++ ++ if( wps_cm == 0 ) ++ sprintf( p->cmd, "iwpriv %s p2p_set prov_disc=%s_display", p->ifname, p->peer_devaddr); ++ else if( wps_cm == 1 ) ++ sprintf( p->cmd, "iwpriv %s p2p_set prov_disc=%s_keypad", p->ifname, p->peer_devaddr); ++ else if( wps_cm == 2 ) ++ sprintf( p->cmd, "iwpriv %s p2p_set prov_disc=%s_pbc", p->ifname, p->peer_devaddr); ++ else if( wps_cm == 3 ) ++ sprintf( p->cmd, "iwpriv %s p2p_set prov_disc=%s_label", p->ifname, p->peer_devaddr); ++ system( p->cmd ); ++ ++} ++#endif ++ ++void p2p_set_nego(struct p2p *p) ++{ ++ FILE *pf=NULL; ++ int retry_count = 0, success = 0; ++ int retry = NEGO_RETRY_INTERVAL, query = NEGO_QUERY_INTERVAL; ++ ++ p->p2p_get=1; ++ memset( p->print_line, 0x00, CMD_SZ ); ++ strcpy( p->print_line, p->nego_msg); ++ ui_screen(p); ++ ++ memset( p->cmd, 0x00, CMD_SZ ); ++ sprintf( p->cmd, "iwpriv %s p2p_set nego=%s ", p->ifname, p->peer_devaddr); ++ system( p->cmd ); ++ ++ usleep( PRE_NEGO_INTERVAL ); ++ ++ p2p_status(p, 0); ++ ++ while( !p2p_check_success(p) && (retry_count < 120 / NEGO_QUERY_INTERVAL )) ++ { ++ retry_count++; ++ ++ if( (retry_count % ( retry / query ) )==0 ) ++ { ++ memset( p->cmd, 0x00, CMD_SZ ); ++ sprintf( p->cmd, "iwpriv %s p2p_set nego=%s ", p->ifname, p->peer_devaddr); ++ system( p->cmd ); ++ ++ usleep( NEGO_QUERY_INTERVAL ); ++ p2p_status(p, 1); ++ } ++ else ++ { ++ ui_screen(p); ++ usleep( NEGO_QUERY_INTERVAL ); ++ p2p_status(p, 1); ++ } ++ } ++ ++ if( p2p_check_success(p) ) ++ { ++ p2p_role(p ,0); ++ p->p2p_get = 1; ++ memset( p->print_line, 0x00, CMD_SZ ); ++ sprintf( p->print_line, "%s", p->ok_msg ); ++ p2p_ifaddr(p); ++ ui_screen(p); ++ ++ if( p->role == P2P_ROLE_CLIENT ) ++ { ++ p2p_client_mode(p); ++ } ++ else if( p->role == P2P_ROLE_GO ) ++ { ++ p2p_get_opch(p); ++ p2p_go_mode(p); ++ } ++ } ++ else ++ { ++ p->p2p_get = 1; ++ p2p_status(p, 0); ++ memset( p->print_line, 0x00, CMD_SZ ); ++ sprintf( p->print_line, "Status= %d, %s", p->status, p->fail_msg ); ++ ui_screen(p); ++ ++#ifdef P2P_ATUO ++ pthread_create(&p->pthread, NULL, &polling_status, (void *)p); ++#endif ++ ++ } ++} ++ ++//After negotiation success, get peer device's interface address. ++void p2p_ifaddr(struct p2p *p) ++{ ++ FILE *pf=NULL; ++ char addr_12[12] = { 0x00 }; ++ int i; ++ ++ /* peer_ifaddr */ ++ memset( p->cmd, 0x00, CMD_SZ ); ++ sprintf( p->cmd, "iwpriv %s p2p_get peer_ifa > status.txt", p->ifname); ++ system( p->cmd ); ++ ++ pf = fopen( "./status.txt", "r" ); ++ if ( pf ) ++ { ++ while( !feof( pf ) ){ ++ memset( p->parse, 0x00, CMD_SZ ); ++ fgets( p->parse, CMD_SZ, pf ); ++ if( strncmp( p->parse, "MAC", 3) == 0 ) ++ { ++ strncpy( p->peer_ifaddr, p->parse+4, 17 ); ++ break; ++ } ++ } ++ fclose( pf ); ++ } ++ ++} ++ ++void p2p_client_mode(struct p2p *p) ++{ ++ FILE *pf = NULL; ++ int count = 0, ret = 0; ++ int inactive_count = 0, inactive_restart = 0; ++ ++ if(p->wpa_open==_TRUE) ++ return; ++ else ++ p->wpa_open = _TRUE; ++ ++ p2p_ifaddr(p); ++ ++ memset( p->cmd, 0x00, CMD_SZ ); ++ sprintf( p->cmd, "%s -i %s -c %s -B ",p->wpa_path, p->ifname, p->wpa_conf); ++ system( p->cmd ); ++ ++ p->p2p_get=1; ++ memset( p->print_line, 0x00, CMD_SZ ); ++ strcpy( p->print_line, "Start wpa_supplicant"); ++ ui_screen(p); ++ ++ usleep( SUPPLICANT_INIT_TIME ); ++ ++ do_wps(p); ++ ++ usleep( SUPPLICANT_INTERVAL ); ++ ++ while( count < WPS_RETRY ) //query status ++ { ++ ++ memset( p->cmd, 0x00, CMD_SZ ); ++ sprintf( p->cmd, "%s status > supp_status.txt", p->wpacli_path); ++ system( p->cmd ); ++ ++ pf = fopen( "./supp_status.txt", "r" ); ++ if ( pf ) ++ { ++ while( !feof( pf ) ){ ++ memset( p->parse, 0x00, CMD_SZ ); ++ fgets( p->parse, CMD_SZ, pf ); ++ if( strncmp( p->parse, "wpa_state=", 10) == 0 ) ++ { ++ int i; ++ if( strncmp( p->parse, "wpa_state=COMPLETED", 19) == 0 ){ ++ count = WPS_RETRY; ++ p->wpsing = _FALSE; ++#ifdef DHCP ++ memset( p->cmd, 0x00, CMD_SZ ); ++ sprintf( p->cmd, "dhclient %s", p->ifname); ++ system( p->cmd ); ++#endif //DHCP ++ } ++ else if( strncmp( p->parse, "wpa_state=INACTIVE", 18) == 0 ){ ++ inactive_count++; ++ if( (inactive_count % 5)== 0) ++ { ++ if( p->wps_info == 2 ) ++ { ++ memset( p->cmd, 0x00, CMD_SZ ); ++ sprintf( p->cmd, "%s wps_pin %s %d > supp_status.txt ", p->wpacli_path, p->peer_ifaddr, p->pin); ++ system( p->cmd ); ++ ++ inactive_restart = 1; ++ } ++ } ++ } ++ ++ if( inactive_restart == 1 ) ++ { ++ inactive_restart = 0; ++ p->p2p_get=1; ++ memset(p->print_line, 0x00, CMD_SZ); ++ sprintf(p->print_line, "Restart WPS"); ++ ui_screen(p); ++ } ++ else ++ { ++ p->p2p_get=1; ++ memset(p->print_line, 0x00, CMD_SZ); ++ for(i=0; iparse[i] == '\n'){ ++ p->parse[i] = ' '; ++ } ++ } ++ sprintf(p->print_line, "%s", p->parse); ++ ui_screen(p); ++ } ++ ++ break; ++ } ++ } ++ ++ fclose( pf ); ++ } ++ ++ count++; ++ usleep( SUPPLICANT_INTERVAL ); ++ ++ } ++ ++ p->wpsing = _FALSE; ++} ++ ++void p2p_go_mode(struct p2p *p) ++{ ++ int count = 0, i = -1; ++ char addr_lower[18]; ++ ++ p2p_ifaddr(p); ++ p->no_sta_connected++; ++ ++ p->p2p_get=1; ++ memset( p->print_line, 0x00, CMD_SZ ); ++ strcpy( p->print_line, "Start hostapd"); ++ ui_screen(p); ++ ++ if(p->ap_open != _TRUE) ++ { ++ memset( p->cmd, 0x00, CMD_SZ ); ++ sprintf( p->cmd, "%s -B %s > temp.txt",p->ap_path, p->ap_conf); ++ system( p->cmd ); ++ ++ usleep( HOSTAPD_INIT_TIME ); ++ p->ap_open = _TRUE; ++ } ++ ++ do_wps(p); ++ ++ usleep( HOSTAPD_INTERVAL ); ++ ++ ++ while( count < WPS_RETRY ) //query status ++ { ++ if( read_all_sta(p) == _TRUE ) ++ { ++ count = WPS_RETRY; ++ p->wpsing = _FALSE; ++ ++ p->p2p_get=1; ++ memset(p->print_line, 0x00, CMD_SZ); ++ for(i=0; iparse[i] == '\n'){ ++ p->parse[i] = ' '; ++ } ++ } ++ sprintf(p->print_line, "%s", p->parse); ++ ui_screen(p); ++#ifdef DHCP ++ memset( p->cmd, 0x00, CMD_SZ ); ++ sprintf( p->cmd, "ifconfig %s 192.168.1.254", p->ifname); ++ system( p->cmd ); ++ ++ usleep(50000); ++ ++ system( "/etc/rc.d/init.d/dhcpd start" ); ++ system( "clear" ); ++#endif //DHCP ++ ++ //After starting hostapd and doing WPS connection successful, ++ //We create a thread to query driver if some other p2p devices connected. ++ p2p_status(p, 0); ++ usleep(50000); ++ ++#ifdef P2P_AUTO ++ p->res_go = pthread_create(&p->pthread_go, NULL, &polling_client, (void *)p); ++ ++ if( p->res_go != 0 ) ++ { ++ p->p2p_get=1; ++ memset( p->print_line, 0x00, CMD_SZ ); ++ sprintf( p->print_line, "Thread creation failed" ); ++ } ++#endif ++ break; ++ } ++ else ++ { ++ if( count == WPS_RETRY) ++ break; ++ ++ count++; ++ usleep( HOSTAPD_INTERVAL ); ++ ++ p->p2p_get=1; ++ memset( p->print_line, 0x00, CMD_SZ ); ++ sprintf( p->print_line, "hostapd open, count:%d", count); ++ ui_screen(p); ++ } ++ } ++ ++ p->wpsing = _FALSE; ++} ++ ++void p2p_get_hostapd_conf(struct p2p *p) ++{ ++ FILE *pf = NULL; ++ ++ pf = fopen( p->ap_conf, "r" ); ++ if ( pf ) ++ { ++ while( !feof( pf ) ){ ++ memset(p->parse, 0x00, CMD_SZ); ++ fgets(p->parse, CMD_SZ, pf); ++ if(strncmp(p->parse, "ssid=", 5) == 0) ++ { ++ strcpy( p->apd_ssid, p->parse+5 ); ++ } ++ else if(strncmp(p->parse, "channel=", 8) == 0) ++ { ++ p->op_ch = atoi( p->parse+8 ); ++ } ++ else if(strncmp(p->parse, "device_name=", 12) == 0) ++ { ++ int i; ++ p->dev_name[0] = '"'; ++ strncpy( p->dev_name+1, p->parse+12, 32 ); ++ for(i=31; i>0; i--) ++ { ++ if(p->dev_name[i] == '\n') ++ { ++ p->dev_name[i]='"'; ++ p->dev_name[i+1]=' '; ++ break; ++ } ++ } ++ } ++ } ++ ++ fclose( pf ); ++ } ++ ++} ++ ++void p2p_set_opch(struct p2p *p, char *msg, int print) ++{ ++ if(print == 1) ++ { ++ p->show_scan_result = 1; ++ ui_screen(p); ++ printf("%s", msg); ++ scanf("%d",&p->op_ch); ++ } ++ ++ memset( p->cmd, 0x00, CMD_SZ ); ++ sprintf( p->cmd, "iwpriv %s p2p_set op_ch=%d", p->ifname, p->op_ch); ++ system( p->cmd ); ++} ++ ++void p2p_softap_ssid(struct p2p *p, char *msg, int print) ++{ ++ if(print == 1) ++ { ++ p->show_scan_result = 1; ++ ui_screen(p); ++ printf("%s", msg); ++ scanf("%s",p->apd_ssid); ++ } ++ ++ memset( p->cmd, 0x00, CMD_SZ ); ++ sprintf( p->cmd, "iwpriv %s p2p_set ssid=%s ", p->ifname, p->apd_ssid); ++ system( p->cmd ); ++} ++ ++void p2p_listen_ch(struct p2p *p, char *msg) ++{ ++ p->show_scan_result = 1; ++ ui_screen(p); ++ printf("%s", msg); ++ scanf("%d",&p->listen_ch); ++ ++ memset( p->cmd, 0x00, CMD_SZ ); ++ sprintf( p->cmd, "iwpriv %s p2p_set listen_ch=%d ", p->ifname, p->listen_ch); ++ system( p->cmd ); ++} ++ ++//When receive provision discovery request, ++//it can show which device address that are connected. ++void p2p_peer_devaddr(struct p2p *p, char *peer_devaddr) ++{ ++ FILE *pf = NULL; ++ char addr_12[12] = { 0x00 }; ++ int i; ++ ++ memset( p->cmd, 0x00, CMD_SZ ); ++ sprintf( p->cmd, "iwpriv %s p2p_get peer_deva > peer.txt", p->ifname); ++ system( p->cmd ); ++ ++ pf = fopen( "./peer.txt", "r" ); ++ if ( pf ) ++ { ++ memset( p->parse, 0x00, CMD_SZ ); ++ fgets( p->parse, CMD_SZ, pf ); ++ fgets( p->parse, CMD_SZ, pf ); ++ strncpy(addr_12, p->parse, 12 ); ++ ++ for(i=0; i<6; i++) ++ { ++ p->peer_devaddr[3*i] = addr_12[2*i]; ++ p->peer_devaddr[3*i+1] = addr_12[2*i+1]; ++ ++ if(i==5) ++ p->peer_devaddr[3*i+2] = '\0'; ++ else ++ p->peer_devaddr[3*i+2] = ':'; ++ } ++ ++ fclose( pf ); ++ ++ } ++ ++} ++ ++//When receive provision discovery request, ++//it can show which config method that want to be as WPS connection. ++void p2p_peer_req_cm(struct p2p *p, char *peer_req_cm) ++{ ++ FILE *pf = NULL; ++ ++ memset( p->cmd, 0x00, CMD_SZ ); ++ sprintf( p->cmd, "iwpriv %s p2p_get req_cm > peer.txt", p->ifname); ++ system( p->cmd ); ++ ++ pf = fopen( "./peer.txt", "r" ); ++ if ( pf ) ++ { ++ while( !feof( pf ) ){ ++ memset( p->parse, 0x00, CMD_SZ ); ++ fgets( p->parse, CMD_SZ, pf ); ++ if( strncmp( p->parse, "CM", 2) == 0 ) ++ { ++ strncpy( peer_req_cm, p->parse+3, 3 ); ++ break; ++ } ++ } ++ fclose( pf ); ++ } ++ ++} ++ ++//When be regotiated passsively and successfully, ++//it will show peer device's peer device address and request config method ++void p2p_peer_info(struct p2p *p, char *peer_devaddr, char *peer_req_cm) ++{ ++ p->p2p_get=1; ++ ++ memset( p->print_line, 0x00, CMD_SZ ); ++ sprintf( p->print_line, "Peer address:%s, req_cm: %s ", peer_devaddr, peer_req_cm); ++ ++} ++ ++//After scan, it will get other devices' supported config methods. ++void p2p_wps_cm(struct p2p *p, char *scan_addr, char *cms) ++{ ++ FILE *pf = NULL; ++ int cm=0, i=0; ++ char parse[100] = {0x00}; ++ memset( cms, 0x00, 30 ); ++ ++ memset( p->cmd, 0x00, CMD_SZ ); ++ sprintf( p->cmd, "iwpriv %s p2p_get2 wpsCM=%s > cm.txt", p->ifname, scan_addr); ++ system( p->cmd ); ++ ++ pf = fopen( "./cm.txt", "r" ); ++ if ( pf ) ++ { ++ while( !feof( pf ) ){ ++ memset( parse, 0x00, CMD_SZ ); ++ fgets( parse, CMD_SZ, pf ); ++ if( strncmp( parse, "M=", 2 ) == 0 ) ++ { ++ cm = atoi( &parse[ 2 ] ); ++ ++ if((cm & WPS_CONFIG_METHOD_LABEL) == WPS_CONFIG_METHOD_LABEL){ ++ strncpy( cms+i, " LAB", 4 ); ++ i=i+4; ++ } ++ if((cm & WPS_CONFIG_METHOD_DISPLAY) == WPS_CONFIG_METHOD_DISPLAY){ ++ if((cm & WPS_CONFIG_METHOD_VDISPLAY) == WPS_CONFIG_METHOD_VDISPLAY){ ++ strncpy( cms+i, " VDIS", 5 ); ++ i=i+5; ++ }else if((cm & WPS_CONFIG_METHOD_PDISPLAY) == WPS_CONFIG_METHOD_PDISPLAY){ ++ strncpy( cms+i, " PDIS", 5 ); ++ i=i+5; ++ }else{ ++ strncpy( cms+i, " DIS", 4 ); ++ i=i+4; ++ } ++ } ++ if((cm & WPS_CONFIG_METHOD_E_NFC) == WPS_CONFIG_METHOD_E_NFC){ ++ strncpy( cms+i, " ENFC", 5 ); ++ i=i+5; ++ } ++ if((cm & WPS_CONFIG_METHOD_I_NFC) == WPS_CONFIG_METHOD_I_NFC){ ++ strncpy( cms+i, " INFC", 5 ); ++ i=i+5; ++ } ++ if((cm & WPS_CONFIG_METHOD_NFC) == WPS_CONFIG_METHOD_NFC){ ++ strncpy( cms+i, " NFC", 4 ); ++ i=i+4; ++ } ++ if((cm & WPS_CONFIG_METHOD_PBC) == WPS_CONFIG_METHOD_PBC){ ++ if((cm & WPS_CONFIG_METHOD_VPBC) == WPS_CONFIG_METHOD_VPBC){ ++ strncpy( cms+i, " VPBC", 5 ); ++ i=i+5; ++ }else if((cm & WPS_CONFIG_METHOD_PPBC) == WPS_CONFIG_METHOD_PPBC){ ++ strncpy( cms+i, " PPBC", 5 ); ++ i=i+5; ++ }else{ ++ strncpy( cms+i, " PBC", 4 ); ++ i=i+4; ++ } ++ } ++ if((cm & WPS_CONFIG_METHOD_KEYPAD) == WPS_CONFIG_METHOD_KEYPAD){ ++ strncpy( cms+i, " PAD", 4 ); ++ i=i+4; ++ } ++ ++ break; ++ } ++ } ++ fclose( pf ); ++ } ++ ++} ++ ++//After scan, it will get other devices' device name. ++void p2p_device_name(struct p2p *p, char *scan_addr, char *dns) ++{ ++ FILE *pf = NULL; ++ int i; ++ char parse[100] = {0x00}; ++ memset( dns, 0x00, 32 ); ++ ++ memset( p->cmd, 0x00, CMD_SZ ); ++ sprintf( p->cmd, "iwpriv %s p2p_get2 devN=%s > cm.txt", p->ifname, scan_addr); ++ system( p->cmd ); ++ ++ pf = fopen( "./cm.txt", "r" ); ++ if ( pf ) ++ { ++ while( !feof( pf ) ){ ++ memset( parse, 0x00, CMD_SZ ); ++ fgets( parse, CMD_SZ, pf ); ++ if( strncmp( parse, "N=", 2) == 0 ) ++ { ++ strncpy( dns, parse+2, 32); ++ for( i=0; i<32; i++) ++ { ++ if(*(dns+i) == '\n'){ ++ *(dns+i) = ' ' ; ++ break; ++ } ++ } ++ ++ break; ++ } ++ } ++ fclose( pf ); ++ } ++} ++ ++//Successively query local device status with interval "POLLING_INTERVAL" ++//when status == P2P_STATE_RX_PROVISION_DIS_REQ, ++//it require user to insert corresponding WPS config method ++void *polling_status(void *arg) ++{ ++ struct p2p *p=(struct p2p*)arg; ++ ++ while( p->res == 0 ){ ++ ++ p2p_status(p, 0); ++ if( (p->status == P2P_STATE_RX_PROVISION_DIS_REQ) || (p->status == P2P_STATE_GONEGO_FAIL) ) ++ { ++ p->thread_trigger = THREAD_DEVICE ; ++ ++ char peer_devaddr[18]; ++ char peer_req_cm[4]; ++ ++ memset( peer_devaddr, 0x00, 18); ++ memset( peer_req_cm, 0x00, 4); ++ ++ p2p_peer_devaddr(p, peer_devaddr); ++ p2p_peer_req_cm(p, peer_req_cm); ++ p2p_peer_info(p, p->peer_devaddr, peer_req_cm); ++ ++ ui_screen(p); ++ ++ //strncpy(p->peer_devaddr, peer_devaddr, 17); ++ if( (strncmp( peer_req_cm, "dis", 3) == 0) || (strncmp( peer_req_cm, "lab", 3) == 0) ) ++ { ++ printf("Here is your PIN, insert c to continue: %d\n", p->pin); ++ } ++ else if( (strncmp( peer_req_cm, "pbc", 3) == 0) ) ++ { ++ printf("Please push b to accept:\n"); ++ } ++ else if( (strncmp( peer_req_cm, "pad", 3) == 0) ) ++ { ++ printf("Please insert peer PIN code:\n"); ++ } ++ ++ break; ++ } ++ ++ usleep( POLLING_INTERVAL ); ++ } ++ ++ return NULL; ++} ++ ++//If p2p device becomes GO, we still polling driver status ++//to check whether some other p2p devices connected ++void *polling_client(void *arg) ++{ ++ struct p2p *p=(struct p2p*)arg; ++ ++ while( p->res_go == 0 ){ ++ ++ if( p->no_sta_connected > 0 && ( p->wpsing == _FALSE ) ) ++ { ++ if( read_all_sta(p) == _FALSE ) ++ { ++ p->no_sta_connected--; ++ } ++ } ++ ++ p2p_status(p, 0); ++ if( p->status == P2P_STATE_RX_PROVISION_DIS_REQ || p->status == P2P_STATE_GONEGO_FAIL || p->status == P2P_STATE_GONEGO_ING ) ++ { ++ p->thread_trigger = THREAD_GO ; ++ ++ char peer_devaddr[18]; ++ char peer_req_cm[4]; ++ ++ memset( peer_devaddr, 0x00, 18); ++ memset( peer_req_cm, 0x00, 4); ++ ++ p2p_peer_devaddr(p, peer_devaddr); ++ p2p_peer_req_cm(p, peer_req_cm); ++ p2p_peer_info(p, p->peer_devaddr, peer_req_cm); ++ ++ ui_screen(p); ++ ++ //strncpy(p->peer_devaddr, peer_devaddr, 17); ++ if( (strncmp( peer_req_cm, "dis", 3) == 0) || (strncmp( peer_req_cm, "lab", 3) == 0) ) ++ { ++ printf("Here is your PIN, insert c to continue: %d\n", p->pin); ++ } ++ else if( (strncmp( peer_req_cm, "pbc", 3) == 0) ) ++ { ++ printf("Please push b to accept:\n", p->status); ++ } ++ else if( (strncmp( peer_req_cm, "pad", 3) == 0) ) ++ { ++ printf("Please insert peer PIN code:\n"); ++ } ++ ++ break; ++ } ++ ++ usleep( POLLING_INTERVAL ); ++ } ++ ++ return NULL; ++} +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/p2p_test.h linux-5.11.4-rtl8812au/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/p2p_test.h +--- linux-5.11.4/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/p2p_test.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/p2p_test.h 2021-03-07 18:16:17.100958228 +0200 +@@ -0,0 +1,167 @@ ++#ifndef _P2P_UI_TEST_H_ ++#define _P2P_UI_TEST_H_ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define P2P_AUTO 1 ++//#define DHCP 1 ++#define CMD_SZ 100 ++#define SSID_SZ 32 ++ ++#define SEC 1000000 ++#define SCAN_POOL_NO 8 ++#define NEGO_RETRY_INTERVAL 10 * SEC ++#define NEGO_QUERY_INTERVAL 0.5 * SEC ++#define PRE_NEGO_INTERVAL 0.5 * SEC ++#define MAX_PROV_RETRY 15 ++#define PROV_RETRY_INTERVAL 5 ++#define PROV_WAIT_TIME 1 * SEC ++#define MAX_NEGO_RETRY 60 ++#define NEGO_WAIT_TIME 0.5 * SEC ++#define WPS_RETRY 120 ++#define SUPPLICANT_INIT_TIME 1 * SEC ++#define HOSTAPD_INIT_TIME 1 * SEC ++#define SUPPLICANT_INTERVAL 1 * SEC ++#define HOSTAPD_INTERVAL 1 * SEC ++#define POLLING_INTERVAL 1 * SEC ++#define _TRUE 1 ++#define _FALSE 0 ++ ++#define WPS_CONFIG_METHOD_LABEL 0x0004 ++#define WPS_CONFIG_METHOD_DISPLAY 0x0008 ++#define WPS_CONFIG_METHOD_E_NFC 0x0010 ++#define WPS_CONFIG_METHOD_I_NFC 0x0020 ++#define WPS_CONFIG_METHOD_NFC 0x0040 ++#define WPS_CONFIG_METHOD_PBC 0x0080 ++#define WPS_CONFIG_METHOD_KEYPAD 0x0100 ++#define WPS_CONFIG_METHOD_VPBC 0x0280 ++#define WPS_CONFIG_METHOD_PPBC 0x0480 ++#define WPS_CONFIG_METHOD_VDISPLAY 0x2008 ++#define WPS_CONFIG_METHOD_PDISPLAY 0x4008 ++ ++enum thread_trigger{ ++ THREAD_NONE = 0, ++ THREAD_DEVICE = 1, ++ THREAD_GO = 2, ++}; ++ ++enum P2P_ROLE { ++ P2P_ROLE_DISABLE = 0, ++ P2P_ROLE_DEVICE = 1, ++ P2P_ROLE_CLIENT = 2, ++ P2P_ROLE_GO = 3 ++}; ++ ++enum P2P_STATE { ++ P2P_STATE_NONE = 0, // P2P disable ++ P2P_STATE_IDLE = 1, // P2P had enabled and do nothing ++ P2P_STATE_LISTEN = 2, // In pure listen state ++ P2P_STATE_SCAN = 3, // In scan phase ++ P2P_STATE_FIND_PHASE_LISTEN = 4, // In the listen state of find phase ++ P2P_STATE_FIND_PHASE_SEARCH = 5, // In the search state of find phase ++ P2P_STATE_TX_PROVISION_DIS_REQ = 6, // In P2P provisioning discovery ++ P2P_STATE_RX_PROVISION_DIS_RSP = 7, ++ P2P_STATE_RX_PROVISION_DIS_REQ = 8, ++ P2P_STATE_GONEGO_ING = 9, // Doing the group owner negoitation handshake ++ P2P_STATE_GONEGO_OK = 10, // finish the group negoitation handshake with success ++ P2P_STATE_GONEGO_FAIL = 11, // finish the group negoitation handshake with failure ++ P2P_STATE_RECV_INVITE_REQ = 12, // receiving the P2P Inviation request ++ P2P_STATE_PROVISIONING_ING = 13, // Doing the P2P WPS ++ P2P_STATE_PROVISIONING_DONE = 14, // Finish the P2P WPS ++}; ++ ++enum P2P_WPSINFO { ++ P2P_NO_WPSINFO = 0, ++ P2P_GOT_WPSINFO_PEER_DISPLAY_PIN = 1, ++ P2P_GOT_WPSINFO_SELF_DISPLAY_PIN = 2, ++ P2P_GOT_WPSINFO_PBC = 3, ++}; ++ ++struct scan{ ++ char addr[18]; ++ int go; ++}; ++ ++struct p2p{ ++ char ifname[10]; ++ int enable; ++ int status; ++ char dev_name[33]; ++ int intent; ++ int listen_ch; ++ int wps_info; ++ int wpsing; ++ unsigned int pin; ++ int role; ++ char peer_devaddr[18]; ++ int p2p_get; //p2p_get==1 : print messages from ioctl p2p_get ++ char print_line[CMD_SZ]; ++ int have_p2p_dev; //have_p2p_dev==1 : after scanning p2p device ++ int show_scan_result; ++ int count_line; ++ char peer_ifaddr[18]; ++ char cmd[CMD_SZ]; ++ char parse[CMD_SZ]; ++ char apd_ssid[SSID_SZ]; ++ int op_ch; //operation channel ++ int wpa_open; ++ int ap_open; ++ char ap_conf[CMD_SZ]; ++ char ap_path[CMD_SZ]; ++ char apcli_path[CMD_SZ]; ++ char wpa_conf[CMD_SZ]; ++ char wpa_path[CMD_SZ]; ++ char wpacli_path[CMD_SZ]; ++ char ok_msg[CMD_SZ]; ++ char redo_msg[CMD_SZ]; ++ char fail_msg[CMD_SZ]; ++ char nego_msg[CMD_SZ]; ++ char scan_msg[CMD_SZ]; ++ int thread_trigger; ++ pthread_t pthread; ++ pthread_t pthread_go; ++ int res; //check if thread is created; 1: disabled, 0: enabled ++ int res_go; //created if p2p device becomes GO ++ struct scan scan_pool[SCAN_POOL_NO]; ++ int connect_go; ++ int no_sta_connected; ++}; ++ ++void ui_screen(struct p2p *p); ++char *naming_wpsinfo(int wps_info); ++char *naming_role(int role); ++char *naming_status(int status); ++unsigned int wps_pin_checksum(unsigned int pin); ++void p2p_enable(struct p2p *p); ++void p2p_scan(struct p2p *p); ++void scan_result(struct p2p *p); ++void p2p_intent(struct p2p *p); ++void p2p_pincode(struct p2p *p, char *ins_no, char *ins_no_again); ++void p2p_devaddr(struct p2p *p); ++void p2p_role(struct p2p *p, int flag); ++void p2p_status(struct p2p *p, int flag); ++void p2p_prov_disc_no_addr(struct p2p *p, char *msg); ++void p2p_prov_disc(struct p2p *p, char *msg, char *dis_msg, char *label_msg); ++void p2p_set_nego(struct p2p *p); ++void p2p_ifaddr(struct p2p *p); ++void p2p_client_mode(struct p2p *p); ++void p2p_go_mode(struct p2p *p); ++void p2p_get_hostapd_conf(struct p2p *p); ++void p2p_set_opch(struct p2p *p, char *msg, int print); ++void p2p_softap_ssid(struct p2p *p, char *msg, int print); ++void p2p_listen_ch(struct p2p *p, char *msg); ++void p2p_peer_devaddr(struct p2p *p, char *peer_devaddr); ++void p2p_peer_req_cm(struct p2p *p, char *peer_req_cm); ++void p2p_peer_info(struct p2p *p, char *peer_devaddr, char *peer_req_cm); ++void p2p_wps_cm(struct p2p *p, char *scan_addr, char *cms); ++void p2p_device_name(struct p2p *p, char *scan_addr, char *dns); ++void p2p_setDN(struct p2p *p); ++void *polling_status(void *arg); ++void *polling_client(void *arg); ++void *print_status(void *arg); ++ ++#endif //_P2P_UI_TEST_H_ +diff -Nurp linux-5.11.4/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/p2p_ui_test_linux.c linux-5.11.4-rtl8812au/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/p2p_ui_test_linux.c +--- linux-5.11.4/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/p2p_ui_test_linux.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.11.4-rtl8812au/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/p2p_ui_test_linux.c 2021-03-07 18:16:17.100958228 +0200 +@@ -0,0 +1,536 @@ ++ ++#include "p2p_test.h" ++ ++char *naming_wpsinfo(int wps_info) ++{ ++ switch(wps_info) ++ { ++ case P2P_NO_WPSINFO: return ("P2P_NO_WPSINFO"); ++ case P2P_GOT_WPSINFO_PEER_DISPLAY_PIN: return ("P2P_GOT_WPSINFO_PEER_DISPLAY_PIN"); ++ case P2P_GOT_WPSINFO_SELF_DISPLAY_PIN: return ("P2P_GOT_WPSINFO_SELF_DISPLAY_PIN"); ++ case P2P_GOT_WPSINFO_PBC: return ("P2P_GOT_WPSINFO_PBC"); ++ default: return ("UI unknown failed"); ++ } ++} ++ ++char *naming_role(int role) ++{ ++ switch(role) ++ { ++ case P2P_ROLE_DISABLE: return ("P2P_ROLE_DISABLE"); ++ case P2P_ROLE_DEVICE: return ("P2P_ROLE_DEVICE"); ++ case P2P_ROLE_CLIENT: return ("P2P_ROLE_CLIENT"); ++ case P2P_ROLE_GO: return ("P2P_ROLE_GO"); ++ default: return ("UI unknown failed"); ++ } ++} ++ ++char *naming_status(int status) ++{ ++ switch(status) ++ { ++ case P2P_STATE_NONE: return ("P2P_STATE_NONE"); ++ case P2P_STATE_IDLE: return ("P2P_STATE_IDLE"); ++ case P2P_STATE_LISTEN: return ("P2P_STATE_LISTEN"); ++ case P2P_STATE_SCAN: return ("P2P_STATE_SCAN"); ++ case P2P_STATE_FIND_PHASE_LISTEN: return ("P2P_STATE_FIND_PHASE_LISTEN"); ++ case P2P_STATE_FIND_PHASE_SEARCH: return ("P2P_STATE_FIND_PHASE_SEARCH"); ++ case P2P_STATE_TX_PROVISION_DIS_REQ: return ("P2P_STATE_TX_PROVISION_DIS_REQ"); ++ case P2P_STATE_RX_PROVISION_DIS_RSP: return ("P2P_STATE_RX_PROVISION_DIS_RSP"); ++ case P2P_STATE_RX_PROVISION_DIS_REQ: return ("P2P_STATE_RX_PROVISION_DIS_REQ"); ++ case P2P_STATE_GONEGO_ING: return ("P2P_STATE_GONEGO_ING"); ++ case P2P_STATE_GONEGO_OK: return ("P2P_STATE_GONEGO_OK"); ++ case P2P_STATE_GONEGO_FAIL: return ("P2P_STATE_GONEGO_FAIL"); ++ case P2P_STATE_RECV_INVITE_REQ: return ("P2P_STATE_RECV_INVITE_REQ"); ++ case P2P_STATE_PROVISIONING_ING: return ("P2P_STATE_PROVISIONING_ING"); ++ case P2P_STATE_PROVISIONING_DONE: return ("P2P_STATE_PROVISIONING_DONE"); ++ default: return ("UI unknown failed"); ++ } ++} ++ ++char* naming_enable(int enable) ++{ ++ switch(enable) ++ { ++ case P2P_ROLE_DISABLE: return ("[Disabled]"); ++ case P2P_ROLE_DEVICE: return ("[Enable/Device]"); ++ case P2P_ROLE_CLIENT: return ("[Enable/Client]"); ++ case P2P_ROLE_GO: return ("[Enable/GO]"); ++ default: return ("UI unknown failed"); ++ } ++} ++ ++void ui_screen(struct p2p *p) ++{ ++ ++ system("clear"); ++ printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); ++ printf("****************************************************************************************************\n"); ++ printf("* P2P UI TEST v0.5 *\n"); ++ printf("****************************************************************************************************\n"); ++ printf("* Enable: %-89s*\n", naming_enable(p->enable)); ++ printf("* Intent: %2d *\n", p->intent); ++ printf("* Status: %-89s*\n", naming_status(p->status)); ++ printf("* Role: %-91s*\n", naming_role(p->role)); ++ printf("* WPS method: %-85s*\n", naming_wpsinfo(p->wps_info)); ++ printf("* PIN code: %08d *\n", p->pin); ++ ++ printf("* Device name: %-84s*\n", p->dev_name); ++ printf("* Peer device address: %-76s*\n", p->peer_devaddr); ++ printf("* Peer interface address: %-73s*\n", p->peer_ifaddr); ++ ++ printf("* *\n"); ++ printf("* e) Wi-Fi Direct Enable/Disable *\n"); ++ printf("* i) Intent ( The degree to be Group Owner/SoftAP ) *\n"); ++ printf("* a) Scan Wi-Fi Direct devices *\n"); ++ printf("* m) Peer device address you want to test *\n"); ++ printf("* p) Provision discovery *\n"); ++ printf("* c) Input PIN codes *\n"); ++ printf("* w) WPS method *\n"); ++ printf("* n) Group owner negotiation *\n"); ++ printf("* x) Start wpa_supplicant/hostapd *\n"); ++ printf("* h) Set operation channel | t) Set SoftAP ssid *\n"); ++ printf("* r) Get Current P2P Role | s) Get Current P2P Status *\n"); ++ printf("* d) Set device name | l) Set Listen channel *\n"); ++ printf("* f) Reflash Current State | q) Quit *\n"); ++ printf("****************************************************************************************************\n"); ++ ++ ++ if(p->p2p_get==0) ++ { ++ printf("* *\n"); ++ } ++ else if(p->p2p_get==1) ++ { ++ printf("*%-98s*\n", p->print_line); ++ } ++ ++ printf("****************************************************************************************************\n"); ++ ++ if( ( p->show_scan_result == 1 ) && ( p->have_p2p_dev == 1 ) ) ++ //if( (p->have_p2p_dev == 1) && (p->enable >= P2P_ROLE_DEVICE) && ( p->wpsing == 0 ) && (p->status >= P2P_STATE_LISTEN && p->status <= P2P_STATE_FIND_PHASE_SEARCH) ) ++ { ++ scan_result(p); ++ } ++ else ++ { ++ int i=0; ++ for(i = 0; i < SCAN_POOL_NO + 1; i++ ) ++ printf("* *\n"); ++ } ++ ++ printf("****************************************************************************************************\n"); ++ ++ p->show_scan_result = 0; ++} ++ ++void init_p2p(struct p2p *p) ++{ ++ strcpy( p->ifname, "wlan0" ); ++ p->enable = P2P_ROLE_DISABLE; ++ p->res = 1; ++ p->res_go = 1; ++ p->status = P2P_STATE_NONE; ++ p->intent = 1; ++ p->wps_info = 0; ++ p->wpsing = 0; ++ p->pin = 12345670; ++ p->role = P2P_ROLE_DISABLE; ++ p->listen_ch = 11; ++ strcpy( p->peer_devaddr, "00:00:00:00:00:00" ); ++ p->p2p_get = 0; ++ memset( p->print_line, 0x00, CMD_SZ); ++ p->have_p2p_dev = 0; ++ p->count_line = 0; ++ strcpy( p->peer_ifaddr, "00:00:00:00:00:00" ); ++ memset( p->cmd, 0x00, CMD_SZ); ++ p->wpa_open=0; ++ p->ap_open=0; ++ strcpy(p->ok_msg, "WiFi Direct handshake done" ); ++ strcpy(p->redo_msg, "Re-do GO handshake" ); ++ strcpy(p->fail_msg, "GO handshake unsuccessful" ); ++ strcpy(p->nego_msg, "Start P2P negotiation" ); ++ strcpy(p->wpa_conf, "./wpa_0_8.conf" ); ++ strcpy(p->wpa_path, "./wpa_supplicant" ); ++ strcpy(p->wpacli_path, "./wpa_cli" ); ++ strcpy(p->ap_conf, "./p2p_hostapd.conf" ); ++ strcpy(p->ap_path, "./hostapd" ); ++ strcpy(p->apcli_path, "./hostapd_cli" ); ++ strcpy(p->scan_msg, "Device haven't enable p2p functionalities" ); ++ ++} ++ ++void rename_intf(struct p2p *p) ++{ ++ FILE *pfin = NULL; ++ FILE *pfout = NULL; ++ ++ pfin = fopen( p->ap_conf, "r" ); ++ pfout = fopen( "./p2p_hostapd_temp.conf", "w" ); ++ ++ if ( pfin ) ++ { ++ while( !feof( pfin ) ){ ++ memset(p->parse, 0x00, CMD_SZ); ++ fgets(p->parse, CMD_SZ, pfin); ++ ++ if(strncmp(p->parse, "interface=", 10) == 0) ++ { ++ memset(p->parse, 0x00, CMD_SZ); ++ sprintf( p->parse, "interface=%s\n", p->ifname ); ++ fputs( p->parse, pfout ); ++ } ++ else ++ fputs(p->parse, pfout); ++ } ++ } ++ ++ fclose( pfout ); ++ ++ system( "rm -rf ./p2p_hostapd.conf" ); ++ system( "mv ./p2p_hostapd_temp.conf ./p2p_hostapd.conf" ); ++ ++ return; ++} ++ ++ ++//int main() ++int main(int argc, char **argv) ++{ ++ char peerifa[40] = { 0x00 }; ++ char scan[CMD_SZ]; ++ struct p2p p2pstruct; ++ struct p2p *p=NULL; ++ ++ p = &p2pstruct; ++ if( p != NULL) ++ { ++ memset(p, 0x00, sizeof(struct p2p)); ++ init_p2p(p); ++ } ++ ++ strcpy(p->ifname, argv[1] ); ++ ++ /* Disable P2P functionalities at first*/ ++ p->enable=P2P_ROLE_DISABLE; ++ p2p_enable(p); ++ p2p_get_hostapd_conf(p); ++ usleep(50000); ++ ++ rename_intf(p); ++ ++ do ++ { ++ ui_screen(p); ++ ++ printf("*insert cmd:"); ++ memset( scan, 0x00, CMD_SZ ); ++ scanf("%s", scan); ++ ++ if( p->thread_trigger == THREAD_NONE ) //Active mode for user interface ++ { ++ ++ if( strncmp(scan, "e", 1) == 0 ) //Enable ++ { ++ p->show_scan_result = 1; ++ ui_screen(p); ++ printf("Please insert enable mode;[0]Disable, [1]Device, [2]Client, [3]GO:"); ++ scanf("%d",&p->enable); ++ ++ p2p_enable(p); ++ p->show_scan_result = 1; ++ } ++ else if( strncmp(scan, "a", 1) == 0 ) // Scan P2P device ++ { ++ p2p_scan(p); ++ p->show_scan_result = 1; ++ } ++ else if( strncmp(scan, "d", 1) == 0 ) // Set device name ++ { ++ p->p2p_get = 0; ++ printf("Please insert device name :"); ++ scanf("\n%[^\n]", p->dev_name); ++ p2p_setDN(p); ++ p->show_scan_result = 1; ++ } ++ else if( strncmp(scan, "i", 1) == 0 ) // Intent ++ { ++ p->show_scan_result = 1; ++ ui_screen(p); ++ printf("Please insert intent from [0~15(must be softap)] :"); ++ scanf("%d",&p->intent); ++ p2p_intent(p); ++ p->show_scan_result = 1; ++ } ++ else if( strncmp(scan, "w", 1) == 0 ) // WPS_info ++ { ++ p->show_scan_result = 1; ++ ui_screen(p); ++ printf("Please insert WPS method\n"); ++ printf("[0]None, [1]Peer Display PIN, [2]Self Display Pin, [3]PBC :"); ++ scanf("%d",&p->wps_info); ++ p2p_wpsinfo(p); ++ p->show_scan_result = 1; ++ } ++ else if( strncmp(scan, "c", 1) == 0 ) // PIN_code ++ { ++ char ins_no[CMD_SZ], ins_no_again[CMD_SZ]; ++ memset(ins_no, 0x00, CMD_SZ); ++ strcpy(ins_no, "Please insert 8-digit number, eg:12345670 :" ); ++ memset(ins_no_again, 0x00, CMD_SZ); ++ strcpy(ins_no_again, "Invalid number, insert again, eg:12345670 :" ); ++ ++ p2p_pincode(p, ins_no, ins_no_again); ++ p->show_scan_result = 1; ++ } ++ else if( strncmp(scan, "m", 1) == 0 ) // Set peer device address ++ { ++ p->show_scan_result = 1; ++ ui_screen(p); ++ printf("Please insert number in scan list:"); ++ p2p_devaddr(p); ++ p->show_scan_result = 1; ++ } ++ else if( strncmp(scan, "r", 1) == 0 ) // Get role ++ { ++ p2p_role(p,1); ++ p->show_scan_result = 1; ++ } ++ else if( strncmp(scan, "s", 1) == 0 ) // Get status ++ { ++ p2p_status(p, 1); ++ p->show_scan_result = 1; ++ } ++ else if( strncmp(scan, "p", 1) == 0 ) // Provision discovery ++ { ++ char msg[CMD_SZ]; ++ memset( msg, 0x00, CMD_SZ ); ++ char dis_msg[CMD_SZ]; ++ memset( dis_msg, 0x00, CMD_SZ ); ++ char label_msg[CMD_SZ]; ++ memset( label_msg, 0x00, CMD_SZ ); ++ ++ ++ if(strncmp(p->peer_devaddr, "00:00:00:00:00:00", 17) == 0) ++ { ++ strcpy( msg, "Please insert peer P2P device at first" ); ++ ++ p2p_prov_disc_no_addr(p, msg); ++ p->show_scan_result = 1; ++ } ++ else ++ { ++ strcpy( msg, "Please insert WPS configuration method ;[0]display, [1]keypad, [2]pbc, [3]label:\n" ); ++ strcpy( dis_msg, "Please insert PIN code displays on peer device screen:" ); ++ strcpy( label_msg, "Please insert PIN code displays on peer label:" ); ++ ++ p2p_prov_disc(p, msg, dis_msg, label_msg); ++ } ++ } ++ else if( strncmp(scan, "n", 1) == 0 ) // Set negotiation ++ { ++ p2p_set_nego(p); ++ } ++ else if( strncmp(scan, "f", 1) == 0 ) // Reflash current state ++ { ++ p->show_scan_result = 1; ++ p2p_status(p, 0); ++ p2p_role(p, 0); ++ p2p_ifaddr(p); ++ ++ if( p->status == P2P_STATE_RX_PROVISION_DIS_REQ ) ++ { ++ char peer_devaddr[18]; ++ char peer_req_cm[4]; ++ ++ memset( peer_devaddr, 0x00, 18); ++ memset( peer_req_cm, 0x00, 4); ++ ++ p2p_peer_devaddr(p, peer_devaddr); ++ p2p_peer_req_cm(p, peer_req_cm); ++ p2p_peer_info(p, p->peer_devaddr, peer_req_cm); ++ } ++#ifndef P2P_AUTO ++ else ++ { ++ if( p->role == P2P_ROLE_CLIENT ) ++ { ++ p2p_client_mode(p); ++ } ++ else if( p->role == P2P_ROLE_GO ) ++ { ++ p2p_go_mode(p); ++ } ++ } ++#endif //P2P_AUTO ++ ++ } ++ else if( strncmp(scan, "x", 1) == 0 ) // Start wpa_supplicant/hostapd ++ { ++ if( p->role == P2P_ROLE_CLIENT ) ++ { ++ p2p_client_mode(p); ++ } ++ else if( p->role == P2P_ROLE_GO ) ++ { ++ p2p_go_mode(p); ++ } ++ } ++ else if( strncmp(scan, "h", 1) == 0 ) // Set operation channel ++ { ++ char msg[CMD_SZ]; ++ memset( msg, 0x00, CMD_SZ ); ++ strcpy( msg, "Please insert desired operation channel:" ); ++ ++ p2p_set_opch(p, msg, 1); ++ p->show_scan_result = 1; ++ } ++ else if( strncmp(scan, "t", 1) == 0 ) // Set SoftAP ssid ++ { ++ char msg[CMD_SZ]; ++ memset( msg, 0x00, CMD_SZ ); ++ strcpy( msg, "Please insert desired SoftAP ssid:" ); ++ ++ p2p_softap_ssid(p, msg, 1); ++ p->show_scan_result = 1; ++ } ++ else if( strncmp(scan, "l", 1) == 0 ) // Set Listen channel ++ { ++ char msg[CMD_SZ]; ++ memset( msg, 0x00, CMD_SZ ); ++ strcpy( msg, "Please insert desired Listen channel, only ch.1.6.11 are available:" ); ++ ++ p2p_listen_ch(p, msg); ++ p->show_scan_result = 1; ++ } ++ else if( strncmp(scan, "q", 1) == 0 ) // Quit ++ { ++ if( p->res == 0 ) ++ p->res = 1; ++ if( p->res_go == 0 ) ++ p->res_go = 1; ++ break; ++ } ++ else // Insert wrong commamd ++ { ++ p->p2p_get=1; ++ p->show_scan_result = 1; ++ memset( p->print_line, 0x00, CMD_SZ ); ++ sprintf( p->print_line, " BAD argument"); ++ } ++ ++ } ++ else if( p->thread_trigger == THREAD_DEVICE ) //Passive mode for user interface ++ { ++ ++ p->thread_trigger = THREAD_NONE ; ++ ++ if( strncmp(scan, "b", 1) == 0 ) ++ { ++ p->wps_info=3; ++ p2p_wpsinfo(p); ++ ++ p2p_status(p, 0); ++ ++ if(p->status != P2P_STATE_GONEGO_OK) ++ { ++ p2p_set_nego(p); ++ } ++ else ++ { ++ p2p_role(p,0); ++ ++ if( p->role == P2P_ROLE_CLIENT ) ++ { ++ p2p_client_mode(p); ++ } ++ else if( p->role == P2P_ROLE_GO ) ++ { ++ p2p_go_mode(p); ++ } ++ } ++ } ++ else if( strncmp(scan, "c", 1) == 0 ) ++ { ++ p->wps_info=2; ++ p2p_wpsinfo(p); ++ ++ p2p_status(p, 0); ++ ++ if(p->status != P2P_STATE_GONEGO_OK) ++ { ++ p2p_set_nego(p); ++ } ++ else ++ { ++ p2p_role(p,0); ++ p2p_ifaddr(p); ++ ++ if( p->role == P2P_ROLE_CLIENT ) ++ { ++ p2p_client_mode(p); ++ } ++ else if( p->role == P2P_ROLE_GO ) ++ { ++ p2p_go_mode(p); ++ } ++ } ++ } ++ else if( ('0' <= *scan ) && ( *scan <= '9') ) ++ { ++ printf("In passive pin code\n"); ++ ++ p->pin = atoi(scan); ++ ++ p->wps_info=1; ++ p2p_wpsinfo(p); ++ ++ p2p_set_nego(p); ++ } ++ } ++ else if( p->thread_trigger == THREAD_GO ) //Passive mode for user interface ++ { ++ ++ p->thread_trigger = THREAD_NONE ; ++ ++ if( strncmp(scan, "b", 1) == 0 ) ++ { ++ p->wps_info=3; ++ p2p_wpsinfo(p); ++ ++ } ++ else if( strncmp(scan, "c", 1) == 0 ) ++ { ++ p->wps_info=2; ++ p2p_wpsinfo(p); ++ } ++ else if( ('0' <= *scan ) && ( *scan <= '9') ) ++ { ++ printf("In passive pin code\n"); ++ ++ p->pin = atoi(scan); ++ ++ p->wps_info=1; ++ p2p_wpsinfo(p); ++ } ++ ++ p2p_go_mode(p); ++ ++ } ++ } ++ while( 1 ); ++ ++ /* Disable P2P functionalities when exits*/ ++ p->enable= -1 ; ++ p2p_enable(p); ++ ++ system( "rm -f ./supp_status.txt" ); ++ system( "rm -f ./temp.txt" ); ++ system( "rm -f ./scan.txt" ); ++ system( "rm -f ./peer.txt" ); ++ system( "rm -f ./status.txt" ); ++ system( "rm -f ./cm.txt" ); ++ ++ return 0; ++ ++} +De binära filerna linux-5.11.4/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/Start_Guide_P2P_User_Interface_Linux.pdf och linux-5.11.4-rtl8812au/3rdparty/rtl8812au/tools/WiFi_Direct_User_Interface/Start_Guide_P2P_User_Interface_Linux.pdf skiljer +De binära filerna linux-5.11.4/3rdparty/rtl8812au/tools/wireless_tools_android.tar.gz och linux-5.11.4-rtl8812au/3rdparty/rtl8812au/tools/wireless_tools_android.tar.gz skiljer diff --git a/kernel/tools/perf/files/patches/mageia/3rd-rtl8821ce-kernel-5.12.patch b/kernel/tools/perf/files/patches/mageia/3rd-rtl8821ce-kernel-5.12.patch new file mode 100644 index 0000000000..f23766d9f9 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/3rd-rtl8821ce-kernel-5.12.patch @@ -0,0 +1,12 @@ +diff -urp linux/3rdparty/rtl8821ce.orig/os_dep/linux/recv_linux.c linux/3rdparty/rtl8821ce/os_dep/linux/recv_linux.c +--- linux/3rdparty/rtl8821ce.orig/os_dep/linux/recv_linux.c 2021-04-26 18:35:37.690041052 +0300 ++++ linux/3rdparty/rtl8821ce/os_dep/linux/recv_linux.c 2021-04-26 18:53:23.534295732 +0300 +@@ -353,7 +353,7 @@ static int napi_recv(_adapter *padapter, + + rx_ok = _FALSE; + +-#ifdef CONFIG_RTW_GRO ++#if defined(CONFIG_RTW_GRO) && LINUX_VERSION_CODE < KERNEL_VERSION(5, 12, 0) + if (pregistrypriv->en_gro) { + if (rtw_napi_gro_receive(&padapter->napi, pskb) != GRO_DROP) + rx_ok = _TRUE; diff --git a/kernel/tools/perf/files/patches/mageia/3rd-rtl8821ce-kernel-5.15.patch b/kernel/tools/perf/files/patches/mageia/3rd-rtl8821ce-kernel-5.15.patch new file mode 100644 index 0000000000..2acf771951 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/3rd-rtl8821ce-kernel-5.15.patch @@ -0,0 +1,66 @@ + +From: +https://github.com/aircrack-ng/rtl8812au/commit/47a38b7c736dd9e9baac9eb07a6dceb83429fb49 + +diff -Nurp linux-5.15/3rdparty/rtl8821ce.orig/core/rtw_br_ext.c linux-5.15/3rdparty/rtl8821ce/core/rtw_br_ext.c +--- linux-5.15/3rdparty/rtl8821ce.orig/core/rtw_br_ext.c 2021-11-08 23:40:48.236272741 +0200 ++++ linux-5.15/3rdparty/rtl8821ce/core/rtw_br_ext.c 2021-11-08 23:49:12.118046953 +0200 +@@ -17,7 +17,10 @@ + #ifdef __KERNEL__ + #include + #include ++ #include ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0) + #include ++#endif + #include + #include + #include +@@ -169,6 +172,7 @@ static __inline__ void __nat25_generate_ + } + + ++#ifdef _NET_INET_IPX_H_ + static __inline__ void __nat25_generate_ipx_network_addr_with_node(unsigned char *networkAddr, + unsigned int *ipxNetAddr, unsigned char *ipxNodeAddr) + { +@@ -189,6 +193,7 @@ static __inline__ void __nat25_generate_ + memcpy(networkAddr + 1, (unsigned char *)ipxNetAddr, 4); + memcpy(networkAddr + 5, (unsigned char *)ipxSocketAddr, 2); + } ++#endif + + + static __inline__ void __nat25_generate_apple_network_addr(unsigned char *networkAddr, +@@ -330,6 +335,7 @@ static __inline__ int __nat25_network_ha + x = networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10]; + + return x & (NAT25_HASH_SIZE - 1); ++#ifdef _NET_INET_IPX_H_ + } else if (networkAddr[0] == NAT25_IPX) { + unsigned long x; + +@@ -337,6 +343,7 @@ static __inline__ int __nat25_network_ha + networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10]; + + return x & (NAT25_HASH_SIZE - 1); ++#endif + } else if (networkAddr[0] == NAT25_APPLE) { + unsigned long x; + +@@ -889,6 +896,7 @@ int nat25_db_handle(_adapter *priv, stru + } + } + ++#ifdef _NET_INET_IPX_H_ + /*---------------------------------------------------*/ + /* Handle IPX and Apple Talk frame */ + /*---------------------------------------------------*/ +@@ -1109,6 +1117,7 @@ int nat25_db_handle(_adapter *priv, stru + + return -1; + } ++#endif + + /*---------------------------------------------------*/ + /* Handle PPPoE frame */ diff --git a/kernel/tools/perf/files/patches/mageia/fs-aufs5.15-symbol-exports.patch b/kernel/tools/perf/files/patches/mageia/fs-aufs5.15-symbol-exports.patch new file mode 100644 index 0000000000..32dab496c6 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/fs-aufs5.15-symbol-exports.patch @@ -0,0 +1,260 @@ + + fs/dcache.c | 2 ++ + fs/exec.c | 1 + + fs/fcntl.c | 1 + + fs/file_table.c | 2 ++ + fs/namespace.c | 3 +++ + fs/notify/group.c | 1 + + fs/open.c | 1 + + fs/read_write.c | 2 ++ + fs/splice.c | 2 ++ + fs/xattr.c | 1 + + kernel/locking/lockdep.c | 1 + + kernel/task_work.c | 1 + + security/security.c | 8 ++++++++ + 13 files changed, 26 insertions(+) + +diff -Nurp linux-5.15.37-aufs/fs/dcache.c linux-5.15.37-aufs-mod/fs/dcache.c +--- linux-5.15.37-aufs/fs/dcache.c 2022-04-08 20:22:30.617616719 +0300 ++++ linux-5.15.37-aufs-mod/fs/dcache.c 2022-04-08 20:24:23.624148779 +0300 +@@ -1450,6 +1450,7 @@ rename_retry: + seq = 1; + goto again; + } ++EXPORT_SYMBOL_GPL(d_walk); + + struct check_mount { + struct vfsmount *mnt; +@@ -2995,6 +2996,7 @@ void d_exchange(struct dentry *dentry1, + + write_sequnlock(&rename_lock); + } ++EXPORT_SYMBOL_GPL(d_exchange); + + /** + * d_ancestor - search for an ancestor +diff -Nurp linux-5.15.37-aufs/fs/exec.c linux-5.15.37-aufs-mod/fs/exec.c +--- linux-5.15.37-aufs/fs/exec.c 2022-04-08 20:07:30.690498863 +0300 ++++ linux-5.15.37-aufs-mod/fs/exec.c 2022-04-08 20:24:23.624148779 +0300 +@@ -112,6 +112,7 @@ bool path_noexec(const struct path *path + return (path->mnt->mnt_flags & MNT_NOEXEC) || + (path->mnt->mnt_sb->s_iflags & SB_I_NOEXEC); + } ++EXPORT_SYMBOL_GPL(path_noexec); + + #ifdef CONFIG_USELIB + /* +diff -Nurp linux-5.15.37-aufs/fs/fcntl.c linux-5.15.37-aufs-mod/fs/fcntl.c +--- linux-5.15.37-aufs/fs/fcntl.c 2022-04-08 20:22:30.617616719 +0300 ++++ linux-5.15.37-aufs-mod/fs/fcntl.c 2022-04-08 20:24:23.624148779 +0300 +@@ -86,6 +86,7 @@ int setfl(int fd, struct file *filp, uns + out: + return error; + } ++EXPORT_SYMBOL_GPL(setfl); + + static void f_modown(struct file *filp, struct pid *pid, enum pid_type type, + int force) +diff -Nurp linux-5.15.37-aufs/fs/file_table.c linux-5.15.37-aufs-mod/fs/file_table.c +--- linux-5.15.37-aufs/fs/file_table.c 2022-03-20 22:14:17.000000000 +0200 ++++ linux-5.15.37-aufs-mod/fs/file_table.c 2022-04-08 20:24:23.624148779 +0300 +@@ -198,6 +198,7 @@ over: + } + return ERR_PTR(-ENFILE); + } ++EXPORT_SYMBOL_GPL(alloc_empty_file); + + /* + * Variant of alloc_empty_file() that doesn't check and modify nr_files. +@@ -412,6 +413,7 @@ void __fput_sync(struct file *file) + } + + EXPORT_SYMBOL(fput); ++EXPORT_SYMBOL_GPL(__fput_sync); + + void __init files_init(void) + { +diff -Nurp linux-5.15.37-aufs/fs/namespace.c linux-5.15.37-aufs-mod/fs/namespace.c +--- linux-5.15.37-aufs/fs/namespace.c 2022-04-08 20:22:30.617616719 +0300 ++++ linux-5.15.37-aufs-mod/fs/namespace.c 2022-04-08 20:24:23.624148779 +0300 +@@ -440,6 +440,7 @@ void __mnt_drop_write(struct vfsmount *m + mnt_dec_writers(real_mount(mnt)); + preempt_enable(); + } ++EXPORT_SYMBOL_GPL(__mnt_drop_write); + + /** + * mnt_drop_write - give up write access to a mount +@@ -844,6 +845,7 @@ int is_current_mnt_ns(struct vfsmount *m + { + return check_mnt(real_mount(mnt)); + } ++EXPORT_SYMBOL_GPL(is_current_mnt_ns); + + /* + * vfsmount lock must be held for write +@@ -2047,6 +2049,7 @@ int iterate_mounts(int (*f)(struct vfsmo + } + return 0; + } ++EXPORT_SYMBOL_GPL(iterate_mounts); + + static void lock_mnt_tree(struct mount *mnt) + { +diff -Nurp linux-5.15.37-aufs/fs/notify/group.c linux-5.15.37-aufs-mod/fs/notify/group.c +--- linux-5.15.37-aufs/fs/notify/group.c 2022-03-20 22:14:17.000000000 +0200 ++++ linux-5.15.37-aufs-mod/fs/notify/group.c 2022-04-08 20:24:23.624148779 +0300 +@@ -100,6 +100,7 @@ void fsnotify_get_group(struct fsnotify_ + { + refcount_inc(&group->refcnt); + } ++EXPORT_SYMBOL_GPL(fsnotify_get_group); + + /* + * Drop a reference to a group. Free it if it's through. +diff -Nurp linux-5.15.37-aufs/fs/open.c linux-5.15.37-aufs-mod/fs/open.c +--- linux-5.15.37-aufs/fs/open.c 2022-03-20 22:14:17.000000000 +0200 ++++ linux-5.15.37-aufs-mod/fs/open.c 2022-04-08 20:24:23.625148828 +0300 +@@ -66,6 +66,7 @@ int do_truncate(struct user_namespace *m + inode_unlock(dentry->d_inode); + return ret; + } ++EXPORT_SYMBOL_GPL(do_truncate); + + long vfs_truncate(const struct path *path, loff_t length) + { +diff -Nurp linux-5.15.37-aufs/fs/read_write.c linux-5.15.37-aufs-mod/fs/read_write.c +--- linux-5.15.37-aufs/fs/read_write.c 2022-03-20 22:14:17.000000000 +0200 ++++ linux-5.15.37-aufs-mod/fs/read_write.c 2022-04-08 20:24:23.625148828 +0300 +@@ -488,6 +488,7 @@ ssize_t vfs_read(struct file *file, char + inc_syscr(current); + return ret; + } ++EXPORT_SYMBOL_GPL(vfs_read); + + static ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos) + { +@@ -598,6 +599,7 @@ ssize_t vfs_write(struct file *file, con + file_end_write(file); + return ret; + } ++EXPORT_SYMBOL_GPL(vfs_write); + + /* file_ppos returns &file->f_pos or NULL if file is stream */ + static inline loff_t *file_ppos(struct file *file) +diff -Nurp linux-5.15.37-aufs/fs/splice.c linux-5.15.37-aufs-mod/fs/splice.c +--- linux-5.15.37-aufs/fs/splice.c 2022-04-08 20:22:30.617616719 +0300 ++++ linux-5.15.37-aufs-mod/fs/splice.c 2022-04-08 20:24:23.625148828 +0300 +@@ -766,6 +766,7 @@ long do_splice_from(struct pipe_inode_in + return warn_unsupported(out, "write"); + return out->f_op->splice_write(pipe, out, ppos, len, flags); + } ++EXPORT_SYMBOL_GPL(do_splice_from); + + /* + * Attempt to initiate a splice from a file to a pipe. +@@ -795,6 +796,7 @@ long do_splice_to(struct file *in, loff_ + return warn_unsupported(in, "read"); + return in->f_op->splice_read(in, ppos, pipe, len, flags); + } ++EXPORT_SYMBOL_GPL(do_splice_to); + + /** + * splice_direct_to_actor - splices data directly between two non-pipes +diff -Nurp linux-5.15.37-aufs/fs/xattr.c linux-5.15.37-aufs-mod/fs/xattr.c +--- linux-5.15.37-aufs/fs/xattr.c 2022-03-20 22:14:17.000000000 +0200 ++++ linux-5.15.37-aufs-mod/fs/xattr.c 2022-04-08 20:24:23.625148828 +0300 +@@ -384,6 +384,7 @@ vfs_getxattr_alloc(struct user_namespace + *xattr_value = value; + return error; + } ++EXPORT_SYMBOL_GPL(vfs_getxattr_alloc); + + ssize_t + __vfs_getxattr(struct dentry *dentry, struct inode *inode, const char *name, +diff -Nurp linux-5.15.37-aufs/kernel/locking/lockdep.c linux-5.15.37-aufs-mod/kernel/locking/lockdep.c +--- linux-5.15.37-aufs/kernel/locking/lockdep.c 2022-04-08 20:22:30.619616817 +0300 ++++ linux-5.15.37-aufs-mod/kernel/locking/lockdep.c 2022-04-08 20:24:23.625148828 +0300 +@@ -208,6 +208,7 @@ inline struct lock_class *lockdep_hlock_ + */ + return lock_classes + class_idx; + } ++EXPORT_SYMBOL_GPL(lockdep_hlock_class); + #define hlock_class(hlock) lockdep_hlock_class(hlock) + + #ifdef CONFIG_LOCK_STAT +diff -Nurp linux-5.15.37-aufs/kernel/task_work.c linux-5.15.37-aufs-mod/kernel/task_work.c +--- linux-5.15.37-aufs/kernel/task_work.c 2022-03-20 22:14:17.000000000 +0200 ++++ linux-5.15.37-aufs-mod/kernel/task_work.c 2022-04-08 20:24:23.625148828 +0300 +@@ -167,3 +167,4 @@ void task_work_run(void) + } while (work); + } + } ++EXPORT_SYMBOL_GPL(task_work_run); +diff -Nurp linux-5.15.37-aufs/security/security.c linux-5.15.37-aufs-mod/security/security.c +--- linux-5.15.37-aufs/security/security.c 2022-04-08 20:07:30.718500239 +0300 ++++ linux-5.15.37-aufs-mod/security/security.c 2022-04-08 20:24:23.626148877 +0300 +@@ -1164,6 +1164,7 @@ int security_path_rmdir(const struct pat + return 0; + return call_int_hook(path_rmdir, 0, dir, dentry); + } ++EXPORT_SYMBOL_GPL(security_path_rmdir); + + int security_path_unlink(const struct path *dir, struct dentry *dentry) + { +@@ -1180,6 +1181,7 @@ int security_path_symlink(const struct p + return 0; + return call_int_hook(path_symlink, 0, dir, dentry, old_name); + } ++EXPORT_SYMBOL_GPL(security_path_symlink); + + int security_path_link(struct dentry *old_dentry, const struct path *new_dir, + struct dentry *new_dentry) +@@ -1188,6 +1190,7 @@ int security_path_link(struct dentry *ol + return 0; + return call_int_hook(path_link, 0, old_dentry, new_dir, new_dentry); + } ++EXPORT_SYMBOL_GPL(security_path_link); + + int security_path_rename(const struct path *old_dir, struct dentry *old_dentry, + const struct path *new_dir, struct dentry *new_dentry, +@@ -1215,6 +1218,7 @@ int security_path_truncate(const struct + return 0; + return call_int_hook(path_truncate, 0, path); + } ++EXPORT_SYMBOL_GPL(security_path_truncate); + + int security_path_chmod(const struct path *path, umode_t mode) + { +@@ -1222,6 +1226,7 @@ int security_path_chmod(const struct pat + return 0; + return call_int_hook(path_chmod, 0, path, mode); + } ++EXPORT_SYMBOL_GPL(security_path_chmod); + + int security_path_chown(const struct path *path, kuid_t uid, kgid_t gid) + { +@@ -1229,6 +1234,7 @@ int security_path_chown(const struct pat + return 0; + return call_int_hook(path_chown, 0, path, uid, gid); + } ++EXPORT_SYMBOL_GPL(security_path_chown); + + int security_path_chroot(const struct path *path) + { +@@ -1329,6 +1335,7 @@ int security_inode_permission(struct ino + return 0; + return call_int_hook(inode_permission, 0, inode, mask); + } ++EXPORT_SYMBOL_GPL(security_inode_permission); + + int security_inode_setattr(struct dentry *dentry, struct iattr *attr) + { +@@ -1526,6 +1533,7 @@ int security_file_permission(struct file + + return fsnotify_perm(file, mask); + } ++EXPORT_SYMBOL_GPL(security_file_permission); + + int security_file_alloc(struct file *file) + { diff --git a/kernel/tools/perf/files/patches/mageia/fs-aufs5.15-tristate.patch b/kernel/tools/perf/files/patches/mageia/fs-aufs5.15-tristate.patch new file mode 100644 index 0000000000..f95f4ab698 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/fs-aufs5.15-tristate.patch @@ -0,0 +1,24 @@ + +Allow aufs to be built as module. + +Signed-off-by: Thomas Backlund + +--- a/fs/aufs/Kconfig ++++ b/fs/aufs/Kconfig +@@ -1,6 +1,6 @@ + # SPDX-License-Identifier: GPL-2.0 + config AUFS_FS +- bool "Aufs (Advanced multi layered unification filesystem) support" ++ tristate "Aufs (Advanced multi layered unification filesystem) support" + help + Aufs is a stackable unification filesystem such as Unionfs, + which unifies several directories and provides a merged single +@@ -72,7 +72,7 @@ endchoice + + config AUFS_EXPORT + bool "NFS-exportable aufs" +- depends on EXPORTFS = y ++ depends on EXPORTFS + help + If you want to export your mounted aufs via NFS, then enable this + option. There are several requirements for this configuration. diff --git a/kernel/tools/perf/files/patches/mageia/fs-aufs5.15.patch b/kernel/tools/perf/files/patches/mageia/fs-aufs5.15.patch new file mode 100644 index 0000000000..3484d64f6f --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/fs-aufs5.15.patch @@ -0,0 +1,38061 @@ + + Documentation/ABI/testing/debugfs-aufs | 55 +++++ + Documentation/ABI/testing/sysfs-aufs | 31 ++ + Documentation/filesystems/aufs/README | 396 ++++++++++++++++++++++++++++++++++++ + Documentation/filesystems/aufs/design/01intro.txt | 158 ++++++++++++++ + Documentation/filesystems/aufs/design/02struct.txt | 245 ++++++++++++++++++++++ + Documentation/filesystems/aufs/design/03atomic_open.txt | 72 ++++++ + Documentation/filesystems/aufs/design/03lookup.txt | 100 +++++++++ + Documentation/filesystems/aufs/design/04branch.txt | 61 +++++ + Documentation/filesystems/aufs/design/05wbr_policy.txt | 51 ++++ + Documentation/filesystems/aufs/design/06dirren.dot | 31 ++ + Documentation/filesystems/aufs/design/06dirren.txt | 89 ++++++++ + Documentation/filesystems/aufs/design/06fhsm.txt | 105 +++++++++ + Documentation/filesystems/aufs/design/06mmap.txt | 59 +++++ + Documentation/filesystems/aufs/design/06xattr.txt | 81 +++++++ + Documentation/filesystems/aufs/design/07export.txt | 45 ++++ + Documentation/filesystems/aufs/design/08shwh.txt | 39 +++ + Documentation/filesystems/aufs/design/10dynop.txt | 34 +++ + MAINTAINERS | 13 + + drivers/block/loop.c | 18 + + fs/Kconfig | 1 + fs/Makefile | 1 + fs/aufs/Kconfig | 199 ++++++++++++++++++ + fs/aufs/Makefile | 39 +++ + fs/aufs/aufs.h | 49 ++++ + fs/aufs/branch.c | 1414 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/aufs/branch.h | 362 ++++++++++++++++++++++++++++++++ + fs/aufs/cpup.c | 1446 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/aufs/cpup.h | 87 +++++++ + fs/aufs/dbgaufs.c | 513 ++++++++++++++++++++++++++++++++++++++++++++++ + fs/aufs/dbgaufs.h | 40 +++ + fs/aufs/dcsub.c | 212 +++++++++++++++++++ + fs/aufs/dcsub.h | 124 +++++++++++ + fs/aufs/debug.c | 431 +++++++++++++++++++++++++++++++++++++++ + fs/aufs/debug.h | 213 +++++++++++++++++++ + fs/aufs/dentry.c | 1155 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/aufs/dentry.h | 256 +++++++++++++++++++++++ + fs/aufs/dinfo.c | 541 +++++++++++++++++++++++++++++++++++++++++++++++++ + fs/aufs/dir.c | 752 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/aufs/dir.h | 121 +++++++++++ + fs/aufs/dirren.c | 1302 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/aufs/dirren.h | 127 +++++++++++ + fs/aufs/dynop.c | 355 ++++++++++++++++++++++++++++++++ + fs/aufs/dynop.h | 64 +++++ + fs/aufs/export.c | 817 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/aufs/f_op.c | 758 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/aufs/fhsm.c | 413 +++++++++++++++++++++++++++++++++++++ + fs/aufs/file.c | 850 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/aufs/file.h | 329 +++++++++++++++++++++++++++++ + fs/aufs/finfo.c | 136 ++++++++++++ + fs/aufs/fsctx.c | 1229 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/aufs/fstype.h | 388 +++++++++++++++++++++++++++++++++++ + fs/aufs/hbl.h | 52 ++++ + fs/aufs/hfsnotify.c | 276 +++++++++++++++++++++++++ + fs/aufs/hfsplus.c | 47 ++++ + fs/aufs/hnotify.c | 702 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/aufs/i_op.c | 1499 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/aufs/i_op_add.c | 928 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/aufs/i_op_del.c | 509 ++++++++++++++++++++++++++++++++++++++++++++++ + fs/aufs/i_op_ren.c | 1244 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/aufs/iinfo.c | 273 ++++++++++++++++++++++++ + fs/aufs/inode.c | 518 +++++++++++++++++++++++++++++++++++++++++++++++ + fs/aufs/inode.h | 692 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/aufs/ioctl.c | 207 ++++++++++++++++++ + fs/aufs/lcnt.h | 173 +++++++++++++++ + fs/aufs/loop.c | 135 ++++++++++++ + fs/aufs/loop.h | 42 +++ + fs/aufs/magic.mk | 31 ++ + fs/aufs/module.c | 259 +++++++++++++++++++++++ + fs/aufs/module.h | 153 +++++++++++++ + fs/aufs/mvdown.c | 693 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/aufs/opts.c | 1019 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/aufs/opts.h | 250 ++++++++++++++++++++++ + fs/aufs/plink.c | 503 +++++++++++++++++++++++++++++++++++++++++++++ + fs/aufs/poll.c | 38 +++ + fs/aufs/posix_acl.c | 98 ++++++++ + fs/aufs/procfs.c | 157 ++++++++++++++ + fs/aufs/rdu.c | 371 +++++++++++++++++++++++++++++++++ + fs/aufs/rwsem.h | 72 ++++++ + fs/aufs/sbinfo.c | 303 +++++++++++++++++++++++++++ + fs/aufs/super.c | 858 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/aufs/super.h | 579 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/aufs/sysaufs.c | 80 +++++++ + fs/aufs/sysaufs.h | 89 ++++++++ + fs/aufs/sysfs.c | 338 ++++++++++++++++++++++++++++++ + fs/aufs/sysrq.c | 136 ++++++++++++ + fs/aufs/vdir.c | 883 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/aufs/vfsub.c | 905 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/aufs/vfsub.h | 345 +++++++++++++++++++++++++++++++ + fs/aufs/wbr_policy.c | 817 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/aufs/whout.c | 1059 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/aufs/whout.h | 74 ++++++ + fs/aufs/wkq.c | 359 ++++++++++++++++++++++++++++++++ + fs/aufs/wkq.h | 76 ++++++ + fs/aufs/xattr.c | 355 ++++++++++++++++++++++++++++++++ + fs/aufs/xino.c | 1913 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/dcache.c | 2 + fs/fcntl.c | 4 + fs/namespace.c | 6 + fs/proc/base.c | 2 + fs/proc/nommu.c | 5 + fs/proc/task_mmu.c | 7 + fs/proc/task_nommu.c | 5 + fs/splice.c | 10 + include/linux/fs.h | 4 + include/linux/lockdep.h | 2 + include/linux/mm.h | 37 +++ + include/linux/mm_types.h | 6 + include/linux/mnt_namespace.h | 3 + include/linux/splice.h | 6 + include/uapi/linux/aufs_type.h | 439 +++++++++++++++++++++++++++++++++++++++ + kernel/fork.c | 2 + kernel/locking/lockdep.c | 3 + mm/Makefile | 1 + mm/filemap.c | 2 + mm/mmap.c | 39 +++ + mm/nommu.c | 10 + mm/prfile.c | 86 +++++++ + 117 files changed, 37172 insertions(+), 26 deletions(-) + +diff -Nurp linux-5.15.37/Documentation/ABI/testing/debugfs-aufs linux-5.15.37-aufs/Documentation/ABI/testing/debugfs-aufs +--- linux-5.15.37/Documentation/ABI/testing/debugfs-aufs 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/Documentation/ABI/testing/debugfs-aufs 2022-04-08 20:22:30.608616279 +0300 +@@ -0,0 +1,55 @@ ++What: /debug/aufs/si_/ ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ Under /debug/aufs, a directory named si_ is created ++ per aufs mount, where is a unique id generated ++ internally. ++ ++What: /debug/aufs/si_/plink ++Date: Apr 2013 ++Contact: J. R. Okajima ++Description: ++ It has three lines and shows the information about the ++ pseudo-link. The first line is a single number ++ representing a number of buckets. The second line is a ++ number of pseudo-links per buckets (separated by a ++ blank). The last line is a single number representing a ++ total number of psedo-links. ++ When the aufs mount option 'noplink' is specified, it ++ will show "1\n0\n0\n". ++ ++What: /debug/aufs/si_/xib ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ It shows the consumed blocks by xib (External Inode Number ++ Bitmap), its block size and file size. ++ When the aufs mount option 'noxino' is specified, it ++ will be empty. About XINO files, see the aufs manual. ++ ++What: /debug/aufs/si_/xi ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ It shows the consumed blocks by xino (External Inode Number ++ Translation Table), its link count, block size and file ++ size. ++ Due to the file size limit, there may exist multiple ++ xino files per branch. In this case, "-N" is added to ++ the filename and it corresponds to the index of the ++ internal xino array. "-0" is omitted. ++ When the aufs mount option 'noxino' is specified, Those ++ entries won't exist. About XINO files, see the aufs ++ manual. ++ ++What: /debug/aufs/si_/xigen ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ It shows the consumed blocks by xigen (External Inode ++ Generation Table), its block size and file size. ++ If CONFIG_AUFS_EXPORT is disabled, this entry will not ++ be created. ++ When the aufs mount option 'noxino' is specified, it ++ will be empty. About XINO files, see the aufs manual. +diff -Nurp linux-5.15.37/Documentation/ABI/testing/sysfs-aufs linux-5.15.37-aufs/Documentation/ABI/testing/sysfs-aufs +--- linux-5.15.37/Documentation/ABI/testing/sysfs-aufs 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/Documentation/ABI/testing/sysfs-aufs 2022-04-08 20:22:30.608616279 +0300 +@@ -0,0 +1,31 @@ ++What: /sys/fs/aufs/si_/ ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ Under /sys/fs/aufs, a directory named si_ is created ++ per aufs mount, where is a unique id generated ++ internally. ++ ++What: /sys/fs/aufs/si_/br ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ It shows the abolute path of a member directory (which ++ is called branch) in aufs, and its permission. ++ ++What: /sys/fs/aufs/si_/brid ++Date: July 2013 ++Contact: J. R. Okajima ++Description: ++ It shows the id of a member directory (which is called ++ branch) in aufs. ++ ++What: /sys/fs/aufs/si_/xi_path ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ It shows the abolute path of XINO (External Inode Number ++ Bitmap, Translation Table and Generation Table) file ++ even if it is the default path. ++ When the aufs mount option 'noxino' is specified, it ++ will be empty. About XINO files, see the aufs manual. +diff -Nurp linux-5.15.37/Documentation/filesystems/aufs/design/01intro.txt linux-5.15.37-aufs/Documentation/filesystems/aufs/design/01intro.txt +--- linux-5.15.37/Documentation/filesystems/aufs/design/01intro.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/Documentation/filesystems/aufs/design/01intro.txt 2022-04-08 20:22:30.609616328 +0300 +@@ -0,0 +1,158 @@ ++ ++# Copyright (C) 2005-2021 Junjiro R. Okajima ++ ++Introduction ++---------------------------------------- ++ ++aufs [ei ju: ef es] | /ey-yoo-ef-es/ | [a u f s] ++1. abbrev. for "advanced multi-layered unification filesystem". ++2. abbrev. for "another unionfs". ++3. abbrev. for "auf das" in German which means "on the" in English. ++ Ex. "Butter aufs Brot"(G) means "butter onto bread"(E). ++ But "Filesystem aufs Filesystem" is hard to understand. ++4. abbrev. for "African Urban Fashion Show". ++ ++AUFS is a filesystem with features: ++- multi layered stackable unification filesystem, the member directory ++ is called as a branch. ++- branch permission and attribute, 'readonly', 'real-readonly', ++ 'readwrite', 'whiteout-able', 'link-able whiteout', etc. and their ++ combination. ++- internal "file copy-on-write". ++- logical deletion, whiteout. ++- dynamic branch manipulation, adding, deleting and changing permission. ++- allow bypassing aufs, user's direct branch access. ++- external inode number translation table and bitmap which maintains the ++ persistent aufs inode number. ++- seekable directory, including NFS readdir. ++- file mapping, mmap and sharing pages. ++- pseudo-link, hardlink over branches. ++- loopback mounted filesystem as a branch. ++- several policies to select one among multiple writable branches. ++- revert a single systemcall when an error occurs in aufs. ++- and more... ++ ++ ++Multi Layered Stackable Unification Filesystem ++---------------------------------------------------------------------- ++Most people already knows what it is. ++It is a filesystem which unifies several directories and provides a ++merged single directory. When users access a file, the access will be ++passed/re-directed/converted (sorry, I am not sure which English word is ++correct) to the real file on the member filesystem. The member ++filesystem is called 'lower filesystem' or 'branch' and has a mode ++'readonly' and 'readwrite.' And the deletion for a file on the lower ++readonly branch is handled by creating 'whiteout' on the upper writable ++branch. ++ ++On LKML, there have been discussions about UnionMount (Jan Blunck, ++Bharata B Rao and Valerie Aurora) and Unionfs (Erez Zadok). They took ++different approaches to implement the merged-view. ++The former tries putting it into VFS, and the latter implements as a ++separate filesystem. ++(If I misunderstand about these implementations, please let me know and ++I shall correct it. Because it is a long time ago when I read their ++source files last time). ++ ++UnionMount's approach will be able to small, but may be hard to share ++branches between several UnionMount since the whiteout in it is ++implemented in the inode on branch filesystem and always ++shared. According to Bharata's post, readdir does not seems to be ++finished yet. ++There are several missing features known in this implementations such as ++- for users, the inode number may change silently. eg. copy-up. ++- link(2) may break by copy-up. ++- read(2) may get an obsoleted filedata (fstat(2) too). ++- fcntl(F_SETLK) may be broken by copy-up. ++- unnecessary copy-up may happen, for example mmap(MAP_PRIVATE) after ++ open(O_RDWR). ++ ++In linux-3.18, "overlay" filesystem (formerly known as "overlayfs") was ++merged into mainline. This is another implementation of UnionMount as a ++separated filesystem. All the limitations and known problems which ++UnionMount are equally inherited to "overlay" filesystem. ++ ++Unionfs has a longer history. When I started implementing a stackable ++filesystem (Aug 2005), it already existed. It has virtual super_block, ++inode, dentry and file objects and they have an array pointing lower ++same kind objects. After contributing many patches for Unionfs, I ++re-started my project AUFS (Jun 2006). ++ ++In AUFS, the structure of filesystem resembles to Unionfs, but I ++implemented my own ideas, approaches and enhancements and it became ++totally different one. ++ ++Comparing DM snapshot and fs based implementation ++- the number of bytes to be copied between devices is much smaller. ++- the type of filesystem must be one and only. ++- the fs must be writable, no readonly fs, even for the lower original ++ device. so the compression fs will not be usable. but if we use ++ loopback mount, we may address this issue. ++ for instance, ++ mount /cdrom/squashfs.img /sq ++ losetup /sq/ext2.img ++ losetup /somewhere/cow ++ dmsetup "snapshot /dev/loop0 /dev/loop1 ..." ++- it will be difficult (or needs more operations) to extract the ++ difference between the original device and COW. ++- DM snapshot-merge may help a lot when users try merging. in the ++ fs-layer union, users will use rsync(1). ++ ++You may want to read my old paper "Filesystems in LiveCD" ++(http://aufs.sourceforge.net/aufs2/report/sq/sq.pdf). ++ ++ ++Several characters/aspects/persona of aufs ++---------------------------------------------------------------------- ++ ++Aufs has several characters, aspects or persona. ++1. a filesystem, callee of VFS helper ++2. sub-VFS, caller of VFS helper for branches ++3. a virtual filesystem which maintains persistent inode number ++4. reader/writer of files on branches such like an application ++ ++1. Callee of VFS Helper ++As an ordinary linux filesystem, aufs is a callee of VFS. For instance, ++unlink(2) from an application reaches sys_unlink() kernel function and ++then vfs_unlink() is called. vfs_unlink() is one of VFS helper and it ++calls filesystem specific unlink operation. Actually aufs implements the ++unlink operation but it behaves like a redirector. ++ ++2. Caller of VFS Helper for Branches ++aufs_unlink() passes the unlink request to the branch filesystem as if ++it were called from VFS. So the called unlink operation of the branch ++filesystem acts as usual. As a caller of VFS helper, aufs should handle ++every necessary pre/post operation for the branch filesystem. ++- acquire the lock for the parent dir on a branch ++- lookup in a branch ++- revalidate dentry on a branch ++- mnt_want_write() for a branch ++- vfs_unlink() for a branch ++- mnt_drop_write() for a branch ++- release the lock on a branch ++ ++3. Persistent Inode Number ++One of the most important issue for a filesystem is to maintain inode ++numbers. This is particularly important to support exporting a ++filesystem via NFS. Aufs is a virtual filesystem which doesn't have a ++backend block device for its own. But some storage is necessary to ++keep and maintain the inode numbers. It may be a large space and may not ++suit to keep in memory. Aufs rents some space from its first writable ++branch filesystem (by default) and creates file(s) on it. These files ++are created by aufs internally and removed soon (currently) keeping ++opened. ++Note: Because these files are removed, they are totally gone after ++ unmounting aufs. It means the inode numbers are not persistent ++ across unmount or reboot. I have a plan to make them really ++ persistent which will be important for aufs on NFS server. ++ ++4. Read/Write Files Internally (copy-on-write) ++Because a branch can be readonly, when you write a file on it, aufs will ++"copy-up" it to the upper writable branch internally. And then write the ++originally requested thing to the file. Generally kernel doesn't ++open/read/write file actively. In aufs, even a single write may cause a ++internal "file copy". This behaviour is very similar to cp(1) command. ++ ++Some people may think it is better to pass such work to user space ++helper, instead of doing in kernel space. Actually I am still thinking ++about it. But currently I have implemented it in kernel space. +diff -Nurp linux-5.15.37/Documentation/filesystems/aufs/design/02struct.txt linux-5.15.37-aufs/Documentation/filesystems/aufs/design/02struct.txt +--- linux-5.15.37/Documentation/filesystems/aufs/design/02struct.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/Documentation/filesystems/aufs/design/02struct.txt 2022-04-08 20:22:30.609616328 +0300 +@@ -0,0 +1,245 @@ ++ ++# Copyright (C) 2005-2021 Junjiro R. Okajima ++ ++Basic Aufs Internal Structure ++ ++Superblock/Inode/Dentry/File Objects ++---------------------------------------------------------------------- ++As like an ordinary filesystem, aufs has its own ++superblock/inode/dentry/file objects. All these objects have a ++dynamically allocated array and store the same kind of pointers to the ++lower filesystem, branch. ++For example, when you build a union with one readwrite branch and one ++readonly, mounted /au, /rw and /ro respectively. ++- /au = /rw + /ro ++- /ro/fileA exists but /rw/fileA ++ ++Aufs lookup operation finds /ro/fileA and gets dentry for that. These ++pointers are stored in a aufs dentry. The array in aufs dentry will be, ++- [0] = NULL (because /rw/fileA doesn't exist) ++- [1] = /ro/fileA ++ ++This style of an array is essentially same to the aufs ++superblock/inode/dentry/file objects. ++ ++Because aufs supports manipulating branches, ie. add/delete/change ++branches dynamically, these objects has its own generation. When ++branches are changed, the generation in aufs superblock is ++incremented. And a generation in other object are compared when it is ++accessed. When a generation in other objects are obsoleted, aufs ++refreshes the internal array. ++ ++ ++Superblock ++---------------------------------------------------------------------- ++Additionally aufs superblock has some data for policies to select one ++among multiple writable branches, XIB files, pseudo-links and kobject. ++See below in detail. ++About the policies which supports copy-down a directory, see ++wbr_policy.txt too. ++ ++ ++Branch and XINO(External Inode Number Translation Table) ++---------------------------------------------------------------------- ++Every branch has its own xino (external inode number translation table) ++file. The xino file is created and unlinked by aufs internally. When two ++members of a union exist on the same filesystem, they share the single ++xino file. ++The struct of a xino file is simple, just a sequence of aufs inode ++numbers which is indexed by the lower inode number. ++In the above sample, assume the inode number of /ro/fileA is i111 and ++aufs assigns the inode number i999 for fileA. Then aufs writes 999 as ++4(8) bytes at 111 * 4(8) bytes offset in the xino file. ++ ++When the inode numbers are not contiguous, the xino file will be sparse ++which has a hole in it and doesn't consume as much disk space as it ++might appear. If your branch filesystem consumes disk space for such ++holes, then you should specify 'xino=' option at mounting aufs. ++ ++Aufs has a mount option to free the disk blocks for such holes in XINO ++files on tmpfs or ramdisk. But it is not so effective actually. If you ++meet a problem of disk shortage due to XINO files, then you should try ++"tmpfs-ino.patch" (and "vfs-ino.patch" too) in aufs4-standalone.git. ++The patch localizes the assignment inumbers per tmpfs-mount and avoid ++the holes in XINO files. ++ ++Also a writable branch has three kinds of "whiteout bases". All these ++are existed when the branch is joined to aufs, and their names are ++whiteout-ed doubly, so that users will never see their names in aufs ++hierarchy. ++1. a regular file which will be hardlinked to all whiteouts. ++2. a directory to store a pseudo-link. ++3. a directory to store an "orphan"-ed file temporary. ++ ++1. Whiteout Base ++ When you remove a file on a readonly branch, aufs handles it as a ++ logical deletion and creates a whiteout on the upper writable branch ++ as a hardlink of this file in order not to consume inode on the ++ writable branch. ++2. Pseudo-link Dir ++ See below, Pseudo-link. ++3. Step-Parent Dir ++ When "fileC" exists on the lower readonly branch only and it is ++ opened and removed with its parent dir, and then user writes ++ something into it, then aufs copies-up fileC to this ++ directory. Because there is no other dir to store fileC. After ++ creating a file under this dir, the file is unlinked. ++ ++Because aufs supports manipulating branches, ie. add/delete/change ++dynamically, a branch has its own id. When the branch order changes, ++aufs finds the new index by searching the branch id. ++ ++ ++Pseudo-link ++---------------------------------------------------------------------- ++Assume "fileA" exists on the lower readonly branch only and it is ++hardlinked to "fileB" on the branch. When you write something to fileA, ++aufs copies-up it to the upper writable branch. Additionally aufs ++creates a hardlink under the Pseudo-link Directory of the writable ++branch. The inode of a pseudo-link is kept in aufs super_block as a ++simple list. If fileB is read after unlinking fileA, aufs returns ++filedata from the pseudo-link instead of the lower readonly ++branch. Because the pseudo-link is based upon the inode, to keep the ++inode number by xino (see above) is essentially necessary. ++ ++All the hardlinks under the Pseudo-link Directory of the writable branch ++should be restored in a proper location later. Aufs provides a utility ++to do this. The userspace helpers executed at remounting and unmounting ++aufs by default. ++During this utility is running, it puts aufs into the pseudo-link ++maintenance mode. In this mode, only the process which began the ++maintenance mode (and its child processes) is allowed to operate in ++aufs. Some other processes which are not related to the pseudo-link will ++be allowed to run too, but the rest have to return an error or wait ++until the maintenance mode ends. If a process already acquires an inode ++mutex (in VFS), it has to return an error. ++ ++ ++XIB(external inode number bitmap) ++---------------------------------------------------------------------- ++Addition to the xino file per a branch, aufs has an external inode number ++bitmap in a superblock object. It is also an internal file such like a ++xino file. ++It is a simple bitmap to mark whether the aufs inode number is in-use or ++not. ++To reduce the file I/O, aufs prepares a single memory page to cache xib. ++ ++As well as XINO files, aufs has a feature to truncate/refresh XIB to ++reduce the number of consumed disk blocks for these files. ++ ++ ++Virtual or Vertical Dir, and Readdir in Userspace ++---------------------------------------------------------------------- ++In order to support multiple layers (branches), aufs readdir operation ++constructs a virtual dir block on memory. For readdir, aufs calls ++vfs_readdir() internally for each dir on branches, merges their entries ++with eliminating the whiteout-ed ones, and sets it to file (dir) ++object. So the file object has its entry list until it is closed. The ++entry list will be updated when the file position is zero and becomes ++obsoleted. This decision is made in aufs automatically. ++ ++The dynamically allocated memory block for the name of entries has a ++unit of 512 bytes (by default) and stores the names contiguously (no ++padding). Another block for each entry is handled by kmem_cache too. ++During building dir blocks, aufs creates hash list and judging whether ++the entry is whiteouted by its upper branch or already listed. ++The merged result is cached in the corresponding inode object and ++maintained by a customizable life-time option. ++ ++Some people may call it can be a security hole or invite DoS attack ++since the opened and once readdir-ed dir (file object) holds its entry ++list and becomes a pressure for system memory. But I'd say it is similar ++to files under /proc or /sys. The virtual files in them also holds a ++memory page (generally) while they are opened. When an idea to reduce ++memory for them is introduced, it will be applied to aufs too. ++For those who really hate this situation, I've developed readdir(3) ++library which operates this merging in userspace. You just need to set ++LD_PRELOAD environment variable, and aufs will not consume no memory in ++kernel space for readdir(3). ++ ++ ++Workqueue ++---------------------------------------------------------------------- ++Aufs sometimes requires privilege access to a branch. For instance, ++in copy-up/down operation. When a user process is going to make changes ++to a file which exists in the lower readonly branch only, and the mode ++of one of ancestor directories may not be writable by a user ++process. Here aufs copy-up the file with its ancestors and they may ++require privilege to set its owner/group/mode/etc. ++This is a typical case of a application character of aufs (see ++Introduction). ++ ++Aufs uses workqueue synchronously for this case. It creates its own ++workqueue. The workqueue is a kernel thread and has privilege. Aufs ++passes the request to call mkdir or write (for example), and wait for ++its completion. This approach solves a problem of a signal handler ++simply. ++If aufs didn't adopt the workqueue and changed the privilege of the ++process, then the process may receive the unexpected SIGXFSZ or other ++signals. ++ ++Also aufs uses the system global workqueue ("events" kernel thread) too ++for asynchronous tasks, such like handling inotify/fsnotify, re-creating a ++whiteout base and etc. This is unrelated to a privilege. ++Most of aufs operation tries acquiring a rw_semaphore for aufs ++superblock at the beginning, at the same time waits for the completion ++of all queued asynchronous tasks. ++ ++ ++Whiteout ++---------------------------------------------------------------------- ++The whiteout in aufs is very similar to Unionfs's. That is represented ++by its filename. UnionMount takes an approach of a file mode, but I am ++afraid several utilities (find(1) or something) will have to support it. ++ ++Basically the whiteout represents "logical deletion" which stops aufs to ++lookup further, but also it represents "dir is opaque" which also stop ++further lookup. ++ ++In aufs, rmdir(2) and rename(2) for dir uses whiteout alternatively. ++In order to make several functions in a single systemcall to be ++revertible, aufs adopts an approach to rename a directory to a temporary ++unique whiteouted name. ++For example, in rename(2) dir where the target dir already existed, aufs ++renames the target dir to a temporary unique whiteouted name before the ++actual rename on a branch, and then handles other actions (make it opaque, ++update the attributes, etc). If an error happens in these actions, aufs ++simply renames the whiteouted name back and returns an error. If all are ++succeeded, aufs registers a function to remove the whiteouted unique ++temporary name completely and asynchronously to the system global ++workqueue. ++ ++ ++Copy-up ++---------------------------------------------------------------------- ++It is a well-known feature or concept. ++When user modifies a file on a readonly branch, aufs operate "copy-up" ++internally and makes change to the new file on the upper writable branch. ++When the trigger systemcall does not update the timestamps of the parent ++dir, aufs reverts it after copy-up. ++ ++ ++Move-down (aufs3.9 and later) ++---------------------------------------------------------------------- ++"Copy-up" is one of the essential feature in aufs. It copies a file from ++the lower readonly branch to the upper writable branch when a user ++changes something about the file. ++"Move-down" is an opposite action of copy-up. Basically this action is ++ran manually instead of automatically and internally. ++For desgin and implementation, aufs has to consider these issues. ++- whiteout for the file may exist on the lower branch. ++- ancestor directories may not exist on the lower branch. ++- diropq for the ancestor directories may exist on the upper branch. ++- free space on the lower branch will reduce. ++- another access to the file may happen during moving-down, including ++ UDBA (see "Revalidate Dentry and UDBA"). ++- the file should not be hard-linked nor pseudo-linked. they should be ++ handled by auplink utility later. ++ ++Sometimes users want to move-down a file from the upper writable branch ++to the lower readonly or writable branch. For instance, ++- the free space of the upper writable branch is going to run out. ++- create a new intermediate branch between the upper and lower branch. ++- etc. ++ ++For this purpose, use "aumvdown" command in aufs-util.git. +diff -Nurp linux-5.15.37/Documentation/filesystems/aufs/design/03atomic_open.txt linux-5.15.37-aufs/Documentation/filesystems/aufs/design/03atomic_open.txt +--- linux-5.15.37/Documentation/filesystems/aufs/design/03atomic_open.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/Documentation/filesystems/aufs/design/03atomic_open.txt 2022-04-08 20:22:30.609616328 +0300 +@@ -0,0 +1,72 @@ ++ ++# Copyright (C) 2015-2021 Junjiro R. Okajima ++ ++Support for a branch who has its ->atomic_open() ++---------------------------------------------------------------------- ++The filesystems who implement its ->atomic_open() are not majority. For ++example NFSv4 does, and aufs should call NFSv4 ->atomic_open, ++particularly for open(O_CREAT|O_EXCL, 0400) case. Other than ++->atomic_open(), NFSv4 returns an error for this open(2). While I am not ++sure whether all filesystems who have ->atomic_open() behave like this, ++but NFSv4 surely returns the error. ++ ++In order to support ->atomic_open() for aufs, there are a few ++approaches. ++ ++A. Introduce aufs_atomic_open() ++ - calls one of VFS:do_last(), lookup_open() or atomic_open() for ++ branch fs. ++B. Introduce aufs_atomic_open() calling create, open and chmod. this is ++ an aufs user Pip Cet's approach ++ - calls aufs_create(), VFS finish_open() and notify_change(). ++ - pass fake-mode to finish_open(), and then correct the mode by ++ notify_change(). ++C. Extend aufs_open() to call branch fs's ->atomic_open() ++ - no aufs_atomic_open(). ++ - aufs_lookup() registers the TID to an aufs internal object. ++ - aufs_create() does nothing when the matching TID is registered, but ++ registers the mode. ++ - aufs_open() calls branch fs's ->atomic_open() when the matching ++ TID is registered. ++D. Extend aufs_open() to re-try branch fs's ->open() with superuser's ++ credential ++ - no aufs_atomic_open(). ++ - aufs_create() registers the TID to an internal object. this info ++ represents "this process created this file just now." ++ - when aufs gets EACCES from branch fs's ->open(), then confirm the ++ registered TID and re-try open() with superuser's credential. ++ ++Pros and cons for each approach. ++ ++A. ++ - straightforward but highly depends upon VFS internal. ++ - the atomic behavaiour is kept. ++ - some of parameters such as nameidata are hard to reproduce for ++ branch fs. ++ - large overhead. ++B. ++ - easy to implement. ++ - the atomic behavaiour is lost. ++C. ++ - the atomic behavaiour is kept. ++ - dirty and tricky. ++ - VFS checks whether the file is created correctly after calling ++ ->create(), which means this approach doesn't work. ++D. ++ - easy to implement. ++ - the atomic behavaiour is lost. ++ - to open a file with superuser's credential and give it to a user ++ process is a bad idea, since the file object keeps the credential ++ in it. It may affect LSM or something. This approach doesn't work ++ either. ++ ++The approach A is ideal, but it hard to implement. So here is a ++variation of A, which is to be implemented. ++ ++A-1. Introduce aufs_atomic_open() ++ - calls branch fs ->atomic_open() if exists. otherwise calls ++ vfs_create() and finish_open(). ++ - the demerit is that the several checks after branch fs ++ ->atomic_open() are lost. in the ordinary case, the checks are ++ done by VFS:do_last(), lookup_open() and atomic_open(). some can ++ be implemented in aufs, but not all I am afraid. +diff -Nurp linux-5.15.37/Documentation/filesystems/aufs/design/03lookup.txt linux-5.15.37-aufs/Documentation/filesystems/aufs/design/03lookup.txt +--- linux-5.15.37/Documentation/filesystems/aufs/design/03lookup.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/Documentation/filesystems/aufs/design/03lookup.txt 2022-04-08 20:22:30.609616328 +0300 +@@ -0,0 +1,100 @@ ++ ++# Copyright (C) 2005-2021 Junjiro R. Okajima ++ ++Lookup in a Branch ++---------------------------------------------------------------------- ++Since aufs has a character of sub-VFS (see Introduction), it operates ++lookup for branches as VFS does. It may be a heavy work. But almost all ++lookup operation in aufs is the simplest case, ie. lookup only an entry ++directly connected to its parent. Digging down the directory hierarchy ++is unnecessary. VFS has a function lookup_one_len() for that use, and ++aufs calls it. ++ ++When a branch is a remote filesystem, aufs basically relies upon its ++->d_revalidate(), also aufs forces the hardest revalidate tests for ++them. ++For d_revalidate, aufs implements three levels of revalidate tests. See ++"Revalidate Dentry and UDBA" in detail. ++ ++ ++Test Only the Highest One for the Directory Permission (dirperm1 option) ++---------------------------------------------------------------------- ++Let's try case study. ++- aufs has two branches, upper readwrite and lower readonly. ++ /au = /rw + /ro ++- "dirA" exists under /ro, but /rw. and its mode is 0700. ++- user invoked "chmod a+rx /au/dirA" ++- the internal copy-up is activated and "/rw/dirA" is created and its ++ permission bits are set to world readable. ++- then "/au/dirA" becomes world readable? ++ ++In this case, /ro/dirA is still 0700 since it exists in readonly branch, ++or it may be a natively readonly filesystem. If aufs respects the lower ++branch, it should not respond readdir request from other users. But user ++allowed it by chmod. Should really aufs rejects showing the entries ++under /ro/dirA? ++ ++To be honest, I don't have a good solution for this case. So aufs ++implements 'dirperm1' and 'nodirperm1' mount options, and leave it to ++users. ++When dirperm1 is specified, aufs checks only the highest one for the ++directory permission, and shows the entries. Otherwise, as usual, checks ++every dir existing on all branches and rejects the request. ++ ++As a side effect, dirperm1 option improves the performance of aufs ++because the number of permission check is reduced when the number of ++branch is many. ++ ++ ++Revalidate Dentry and UDBA (User's Direct Branch Access) ++---------------------------------------------------------------------- ++Generally VFS helpers re-validate a dentry as a part of lookup. ++0. digging down the directory hierarchy. ++1. lock the parent dir by its i_mutex. ++2. lookup the final (child) entry. ++3. revalidate it. ++4. call the actual operation (create, unlink, etc.) ++5. unlock the parent dir ++ ++If the filesystem implements its ->d_revalidate() (step 3), then it is ++called. Actually aufs implements it and checks the dentry on a branch is ++still valid. ++But it is not enough. Because aufs has to release the lock for the ++parent dir on a branch at the end of ->lookup() (step 2) and ++->d_revalidate() (step 3) while the i_mutex of the aufs dir is still ++held by VFS. ++If the file on a branch is changed directly, eg. bypassing aufs, after ++aufs released the lock, then the subsequent operation may cause ++something unpleasant result. ++ ++This situation is a result of VFS architecture, ->lookup() and ++->d_revalidate() is separated. But I never say it is wrong. It is a good ++design from VFS's point of view. It is just not suitable for sub-VFS ++character in aufs. ++ ++Aufs supports such case by three level of revalidation which is ++selectable by user. ++1. Simple Revalidate ++ Addition to the native flow in VFS's, confirm the child-parent ++ relationship on the branch just after locking the parent dir on the ++ branch in the "actual operation" (step 4). When this validation ++ fails, aufs returns EBUSY. ->d_revalidate() (step 3) in aufs still ++ checks the validation of the dentry on branches. ++2. Monitor Changes Internally by Inotify/Fsnotify ++ Addition to above, in the "actual operation" (step 4) aufs re-lookup ++ the dentry on the branch, and returns EBUSY if it finds different ++ dentry. ++ Additionally, aufs sets the inotify/fsnotify watch for every dir on branches ++ during it is in cache. When the event is notified, aufs registers a ++ function to kernel 'events' thread by schedule_work(). And the ++ function sets some special status to the cached aufs dentry and inode ++ private data. If they are not cached, then aufs has nothing to ++ do. When the same file is accessed through aufs (step 0-3) later, ++ aufs will detect the status and refresh all necessary data. ++ In this mode, aufs has to ignore the event which is fired by aufs ++ itself. ++3. No Extra Validation ++ This is the simplest test and doesn't add any additional revalidation ++ test, and skip the revalidation in step 4. It is useful and improves ++ aufs performance when system surely hide the aufs branches from user, ++ by over-mounting something (or another method). +diff -Nurp linux-5.15.37/Documentation/filesystems/aufs/design/04branch.txt linux-5.15.37-aufs/Documentation/filesystems/aufs/design/04branch.txt +--- linux-5.15.37/Documentation/filesystems/aufs/design/04branch.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/Documentation/filesystems/aufs/design/04branch.txt 2022-04-08 20:22:30.609616328 +0300 +@@ -0,0 +1,61 @@ ++ ++# Copyright (C) 2005-2021 Junjiro R. Okajima ++ ++Branch Manipulation ++ ++Since aufs supports dynamic branch manipulation, ie. add/remove a branch ++and changing its permission/attribute, there are a lot of works to do. ++ ++ ++Add a Branch ++---------------------------------------------------------------------- ++o Confirm the adding dir exists outside of aufs, including loopback ++ mount, and its various attributes. ++o Initialize the xino file and whiteout bases if necessary. ++ See struct.txt. ++ ++o Check the owner/group/mode of the directory ++ When the owner/group/mode of the adding directory differs from the ++ existing branch, aufs issues a warning because it may impose a ++ security risk. ++ For example, when a upper writable branch has a world writable empty ++ top directory, a malicious user can create any files on the writable ++ branch directly, like copy-up and modify manually. If something like ++ /etc/{passwd,shadow} exists on the lower readonly branch but the upper ++ writable branch, and the writable branch is world-writable, then a ++ malicious guy may create /etc/passwd on the writable branch directly ++ and the infected file will be valid in aufs. ++ I am afraid it can be a security issue, but aufs can do nothing except ++ producing a warning. ++ ++ ++Delete a Branch ++---------------------------------------------------------------------- ++o Confirm the deleting branch is not busy ++ To be general, there is one merit to adopt "remount" interface to ++ manipulate branches. It is to discard caches. At deleting a branch, ++ aufs checks the still cached (and connected) dentries and inodes. If ++ there are any, then they are all in-use. An inode without its ++ corresponding dentry can be alive alone (for example, inotify/fsnotify case). ++ ++ For the cached one, aufs checks whether the same named entry exists on ++ other branches. ++ If the cached one is a directory, because aufs provides a merged view ++ to users, as long as one dir is left on any branch aufs can show the ++ dir to users. In this case, the branch can be removed from aufs. ++ Otherwise aufs rejects deleting the branch. ++ ++ If any file on the deleting branch is opened by aufs, then aufs ++ rejects deleting. ++ ++ ++Modify the Permission of a Branch ++---------------------------------------------------------------------- ++o Re-initialize or remove the xino file and whiteout bases if necessary. ++ See struct.txt. ++ ++o rw --> ro: Confirm the modifying branch is not busy ++ Aufs rejects the request if any of these conditions are true. ++ - a file on the branch is mmap-ed. ++ - a regular file on the branch is opened for write and there is no ++ same named entry on the upper branch. +diff -Nurp linux-5.15.37/Documentation/filesystems/aufs/design/05wbr_policy.txt linux-5.15.37-aufs/Documentation/filesystems/aufs/design/05wbr_policy.txt +--- linux-5.15.37/Documentation/filesystems/aufs/design/05wbr_policy.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/Documentation/filesystems/aufs/design/05wbr_policy.txt 2022-04-08 20:22:30.609616328 +0300 +@@ -0,0 +1,51 @@ ++ ++# Copyright (C) 2005-2021 Junjiro R. Okajima ++ ++Policies to Select One among Multiple Writable Branches ++---------------------------------------------------------------------- ++When the number of writable branch is more than one, aufs has to decide ++the target branch for file creation or copy-up. By default, the highest ++writable branch which has the parent (or ancestor) dir of the target ++file is chosen (top-down-parent policy). ++By user's request, aufs implements some other policies to select the ++writable branch, for file creation several policies, round-robin, ++most-free-space, and other policies. For copy-up, top-down-parent, ++bottom-up-parent, bottom-up and others. ++ ++As expected, the round-robin policy selects the branch in circular. When ++you have two writable branches and creates 10 new files, 5 files will be ++created for each branch. mkdir(2) systemcall is an exception. When you ++create 10 new directories, all will be created on the same branch. ++And the most-free-space policy selects the one which has most free ++space among the writable branches. The amount of free space will be ++checked by aufs internally, and users can specify its time interval. ++ ++The policies for copy-up is more simple, ++top-down-parent is equivalent to the same named on in create policy, ++bottom-up-parent selects the writable branch where the parent dir ++exists and the nearest upper one from the copyup-source, ++bottom-up selects the nearest upper writable branch from the ++copyup-source, regardless the existence of the parent dir. ++ ++There are some rules or exceptions to apply these policies. ++- If there is a readonly branch above the policy-selected branch and ++ the parent dir is marked as opaque (a variation of whiteout), or the ++ target (creating) file is whiteout-ed on the upper readonly branch, ++ then the result of the policy is ignored and the target file will be ++ created on the nearest upper writable branch than the readonly branch. ++- If there is a writable branch above the policy-selected branch and ++ the parent dir is marked as opaque or the target file is whiteouted ++ on the branch, then the result of the policy is ignored and the target ++ file will be created on the highest one among the upper writable ++ branches who has diropq or whiteout. In case of whiteout, aufs removes ++ it as usual. ++- link(2) and rename(2) systemcalls are exceptions in every policy. ++ They try selecting the branch where the source exists as possible ++ since copyup a large file will take long time. If it can't be, ++ ie. the branch where the source exists is readonly, then they will ++ follow the copyup policy. ++- There is an exception for rename(2) when the target exists. ++ If the rename target exists, aufs compares the index of the branches ++ where the source and the target exists and selects the higher ++ one. If the selected branch is readonly, then aufs follows the ++ copyup policy. +diff -Nurp linux-5.15.37/Documentation/filesystems/aufs/design/06dirren.dot linux-5.15.37-aufs/Documentation/filesystems/aufs/design/06dirren.dot +--- linux-5.15.37/Documentation/filesystems/aufs/design/06dirren.dot 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/Documentation/filesystems/aufs/design/06dirren.dot 2022-04-08 20:22:30.609616328 +0300 +@@ -0,0 +1,31 @@ ++ ++// to view this graph, run dot(1) command in GRAPHVIZ. ++ ++digraph G { ++node [shape=box]; ++whinfo [label="detailed info file\n(lower_brid_root-hinum, h_inum, namelen, old name)"]; ++ ++node [shape=oval]; ++ ++aufs_rename -> whinfo [label="store/remove"]; ++ ++node [shape=oval]; ++inode_list [label="h_inum list in branch\ncache"]; ++ ++node [shape=box]; ++whinode [label="h_inum list file"]; ++ ++node [shape=oval]; ++brmgmt [label="br_add/del/mod/umount"]; ++ ++brmgmt -> inode_list [label="create/remove"]; ++brmgmt -> whinode [label="load/store"]; ++ ++inode_list -> whinode [style=dashed,dir=both]; ++ ++aufs_rename -> inode_list [label="add/del"]; ++ ++aufs_lookup -> inode_list [label="search"]; ++ ++aufs_lookup -> whinfo [label="load/remove"]; ++} +diff -Nurp linux-5.15.37/Documentation/filesystems/aufs/design/06dirren.txt linux-5.15.37-aufs/Documentation/filesystems/aufs/design/06dirren.txt +--- linux-5.15.37/Documentation/filesystems/aufs/design/06dirren.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/Documentation/filesystems/aufs/design/06dirren.txt 2022-04-08 20:22:30.609616328 +0300 +@@ -0,0 +1,89 @@ ++ ++# Copyright (C) 2017-2021 Junjiro R. Okajima ++ ++Special handling for renaming a directory (DIRREN) ++---------------------------------------------------------------------- ++First, let's assume we have a simple usecase. ++ ++- /u = /rw + /ro ++- /rw/dirA exists ++- /ro/dirA and /ro/dirA/file exist too ++- there is no dirB on both branches ++- a user issues rename("dirA", "dirB") ++ ++Now, what should aufs behave against this rename(2)? ++There are a few possible cases. ++ ++A. returns EROFS. ++ since dirA exists on a readonly branch which cannot be renamed. ++B. returns EXDEV. ++ it is possible to copy-up dirA (only the dir itself), but the child ++ entries ("file" in this case) should not be. it must be a bad ++ approach to copy-up recursively. ++C. returns a success. ++ even the branch /ro is readonly, aufs tries renaming it. Obviously it ++ is a violation of aufs' policy. ++D. construct an extra information which indicates that /ro/dirA should ++ be handled as the name of dirB. ++ overlayfs has a similar feature called REDIRECT. ++ ++Until now, aufs implements the case B only which returns EXDEV, and ++expects the userspace application behaves like mv(1) which tries ++issueing rename(2) recursively. ++ ++A new aufs feature called DIRREN is introduced which implements the case ++D. There are several "extra information" added. ++ ++1. detailed info per renamed directory ++ path: /rw/dirB/$AUFS_WH_DR_INFO_PFX. ++2. the inode-number list of directories on a branch ++ path: /rw/dirB/$AUFS_WH_DR_BRHINO ++ ++The filename of "detailed info per directory" represents the lower ++branch, and its format is ++- a type of the branch id ++ one of these. ++ + uuid (not implemented yet) ++ + fsid ++ + dev ++- the inode-number of the branch root dir ++ ++And it contains these info in a single regular file. ++- magic number ++- branch's inode-number of the logically renamed dir ++- the name of the before-renamed dir ++ ++The "detailed info per directory" file is created in aufs rename(2), and ++loaded in any lookup. ++The info is considered in lookup for the matching case only. Here ++"matching" means that the root of branch (in the info filename) is same ++to the current looking-up branch. After looking-up the before-renamed ++name, the inode-number is compared. And the matched dentry is used. ++ ++The "inode-number list of directories" is a regular file which contains ++simply the inode-numbers on the branch. The file is created or updated ++in removing the branch, and loaded in adding the branch. Its lifetime is ++equal to the branch. ++The list is refered in lookup, and when the current target inode is ++found in the list, the aufs tries loading the "detailed info per ++directory" and get the changed and valid name of the dir. ++ ++Theoretically these "extra informaiton" may be able to be put into XATTR ++in the dir inode. But aufs doesn't choose this way because ++1. XATTR may not be supported by the branch (or its configuration) ++2. XATTR may have its size limit. ++3. XATTR may be less easy to convert than a regular file, when the ++ format of the info is changed in the future. ++At the same time, I agree that the regular file approach is much slower ++than XATTR approach. So, in the future, aufs may take the XATTR or other ++better approach. ++ ++This DIRREN feature is enabled by aufs configuration, and is activated ++by a new mount option. ++ ++For the more complicated case, there is a work with UDBA option, which ++is to dected the direct access to the branches (by-passing aufs) and to ++maintain the cashes in aufs. Since a single cached aufs dentry may ++contains two names, before- and after-rename, the name comparision in ++UDBA handler may not work correctly. In this case, the behaviour will be ++equivalen to udba=reval case. +diff -Nurp linux-5.15.37/Documentation/filesystems/aufs/design/06fhsm.txt linux-5.15.37-aufs/Documentation/filesystems/aufs/design/06fhsm.txt +--- linux-5.15.37/Documentation/filesystems/aufs/design/06fhsm.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/Documentation/filesystems/aufs/design/06fhsm.txt 2022-04-08 20:22:30.609616328 +0300 +@@ -0,0 +1,105 @@ ++ ++# Copyright (C) 2011-2021 Junjiro R. Okajima ++ ++File-based Hierarchical Storage Management (FHSM) ++---------------------------------------------------------------------- ++Hierarchical Storage Management (or HSM) is a well-known feature in the ++storage world. Aufs provides this feature as file-based with multiple ++writable branches, based upon the principle of "Colder, the Lower". ++Here the word "colder" means that the less used files, and "lower" means ++that the position in the order of the stacked branches vertically. ++These multiple writable branches are prioritized, ie. the topmost one ++should be the fastest drive and be used heavily. ++ ++o Characters in aufs FHSM story ++- aufs itself and a new branch attribute. ++- a new ioctl interface to move-down and to establish a connection with ++ the daemon ("move-down" is a converse of "copy-up"). ++- userspace tool and daemon. ++ ++The userspace daemon establishes a connection with aufs and waits for ++the notification. The notified information is very similar to struct ++statfs containing the number of consumed blocks and inodes. ++When the consumed blocks/inodes of a branch exceeds the user-specified ++upper watermark, the daemon activates its move-down process until the ++consumed blocks/inodes reaches the user-specified lower watermark. ++ ++The actual move-down is done by aufs based upon the request from ++user-space since we need to maintain the inode number and the internal ++pointer arrays in aufs. ++ ++Currently aufs FHSM handles the regular files only. Additionally they ++must not be hard-linked nor pseudo-linked. ++ ++ ++o Cowork of aufs and the user-space daemon ++ During the userspace daemon established the connection, aufs sends a ++ small notification to it whenever aufs writes something into the ++ writable branch. But it may cost high since aufs issues statfs(2) ++ internally. So user can specify a new option to cache the ++ info. Actually the notification is controlled by these factors. ++ + the specified cache time. ++ + classified as "force" by aufs internally. ++ Until the specified time expires, aufs doesn't send the info ++ except the forced cases. When aufs decide forcing, the info is always ++ notified to userspace. ++ For example, the number of free inodes is generally large enough and ++ the shortage of it happens rarely. So aufs doesn't force the ++ notification when creating a new file, directory and others. This is ++ the typical case which aufs doesn't force. ++ When aufs writes the actual filedata and the files consumes any of new ++ blocks, the aufs forces notifying. ++ ++ ++o Interfaces in aufs ++- New branch attribute. ++ + fhsm ++ Specifies that the branch is managed by FHSM feature. In other word, ++ participant in the FHSM. ++ When nofhsm is set to the branch, it will not be the source/target ++ branch of the move-down operation. This attribute is set ++ independently from coo and moo attributes, and if you want full ++ FHSM, you should specify them as well. ++- New mount option. ++ + fhsm_sec ++ Specifies a second to suppress many less important info to be ++ notified. ++- New ioctl. ++ + AUFS_CTL_FHSM_FD ++ create a new file descriptor which userspace can read the notification ++ (a subset of struct statfs) from aufs. ++- Module parameter 'brs' ++ It has to be set to 1. Otherwise the new mount option 'fhsm' will not ++ be set. ++- mount helpers /sbin/mount.aufs and /sbin/umount.aufs ++ When there are two or more branches with fhsm attributes, ++ /sbin/mount.aufs invokes the user-space daemon and /sbin/umount.aufs ++ terminates it. As a result of remounting and branch-manipulation, the ++ number of branches with fhsm attribute can be one. In this case, ++ /sbin/mount.aufs will terminate the user-space daemon. ++ ++ ++Finally the operation is done as these steps in kernel-space. ++- make sure that, ++ + no one else is using the file. ++ + the file is not hard-linked. ++ + the file is not pseudo-linked. ++ + the file is a regular file. ++ + the parent dir is not opaqued. ++- find the target writable branch. ++- make sure the file is not whiteout-ed by the upper (than the target) ++ branch. ++- make the parent dir on the target branch. ++- mutex lock the inode on the branch. ++- unlink the whiteout on the target branch (if exists). ++- lookup and create the whiteout-ed temporary name on the target branch. ++- copy the file as the whiteout-ed temporary name on the target branch. ++- rename the whiteout-ed temporary name to the original name. ++- unlink the file on the source branch. ++- maintain the internal pointer array and the external inode number ++ table (XINO). ++- maintain the timestamps and other attributes of the parent dir and the ++ file. ++ ++And of course, in every step, an error may happen. So the operation ++should restore the original file state after an error happens. +diff -Nurp linux-5.15.37/Documentation/filesystems/aufs/design/06mmap.txt linux-5.15.37-aufs/Documentation/filesystems/aufs/design/06mmap.txt +--- linux-5.15.37/Documentation/filesystems/aufs/design/06mmap.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/Documentation/filesystems/aufs/design/06mmap.txt 2022-04-08 20:22:30.609616328 +0300 +@@ -0,0 +1,59 @@ ++ ++# Copyright (C) 2005-2021 Junjiro R. Okajima ++ ++mmap(2) -- File Memory Mapping ++---------------------------------------------------------------------- ++In aufs, the file-mapped pages are handled by a branch fs directly, no ++interaction with aufs. It means aufs_mmap() calls the branch fs's ++->mmap(). ++This approach is simple and good, but there is one problem. ++Under /proc, several entries show the mmapped files by its path (with ++device and inode number), and the printed path will be the path on the ++branch fs's instead of virtual aufs's. ++This is not a problem in most cases, but some utilities lsof(1) (and its ++user) may expect the path on aufs. ++ ++To address this issue, aufs adds a new member called vm_prfile in struct ++vm_area_struct (and struct vm_region). The original vm_file points to ++the file on the branch fs in order to handle everything correctly as ++usual. The new vm_prfile points to a virtual file in aufs, and the ++show-functions in procfs refers to vm_prfile if it is set. ++Also we need to maintain several other places where touching vm_file ++such like ++- fork()/clone() copies vma and the reference count of vm_file is ++ incremented. ++- merging vma maintains the ref count too. ++ ++This is not a good approach. It just fakes the printed path. But it ++leaves all behaviour around f_mapping unchanged. This is surely an ++advantage. ++Actually aufs had adopted another complicated approach which calls ++generic_file_mmap() and handles struct vm_operations_struct. In this ++approach, aufs met a hard problem and I could not solve it without ++switching the approach. ++ ++There may be one more another approach which is ++- bind-mount the branch-root onto the aufs-root internally ++- grab the new vfsmount (ie. struct mount) ++- lazy-umount the branch-root internally ++- in open(2) the aufs-file, open the branch-file with the hidden ++ vfsmount (instead of the original branch's vfsmount) ++- ideally this "bind-mount and lazy-umount" should be done atomically, ++ but it may be possible from userspace by the mount helper. ++ ++Adding the internal hidden vfsmount and using it in opening a file, the ++file path under /proc will be printed correctly. This approach looks ++smarter, but is not possible I am afraid. ++- aufs-root may be bind-mount later. when it happens, another hidden ++ vfsmount will be required. ++- it is hard to get the chance to bind-mount and lazy-umount ++ + in kernel-space, FS can have vfsmount in open(2) via ++ file->f_path, and aufs can know its vfsmount. But several locks are ++ already acquired, and if aufs tries to bind-mount and lazy-umount ++ here, then it may cause a deadlock. ++ + in user-space, bind-mount doesn't invoke the mount helper. ++- since /proc shows dev and ino, aufs has to give vma these info. it ++ means a new member vm_prinode will be necessary. this is essentially ++ equivalent to vm_prfile described above. ++ ++I have to give up this "looks-smater" approach. +diff -Nurp linux-5.15.37/Documentation/filesystems/aufs/design/06xattr.txt linux-5.15.37-aufs/Documentation/filesystems/aufs/design/06xattr.txt +--- linux-5.15.37/Documentation/filesystems/aufs/design/06xattr.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/Documentation/filesystems/aufs/design/06xattr.txt 2022-04-08 20:22:30.609616328 +0300 +@@ -0,0 +1,81 @@ ++ ++# Copyright (C) 2014-2021 Junjiro R. Okajima ++ ++Listing XATTR/EA and getting the value ++---------------------------------------------------------------------- ++For the inode standard attributes (owner, group, timestamps, etc.), aufs ++shows the values from the topmost existing file. This behaviour is good ++for the non-dir entries since the bahaviour exactly matches the shown ++information. But for the directories, aufs considers all the same named ++entries on the lower branches. Which means, if one of the lower entry ++rejects readdir call, then aufs returns an error even if the topmost ++entry allows it. This behaviour is necessary to respect the branch fs's ++security, but can make users confused since the user-visible standard ++attributes don't match the behaviour. ++To address this issue, aufs has a mount option called dirperm1 which ++checks the permission for the topmost entry only, and ignores the lower ++entry's permission. ++ ++A similar issue can happen around XATTR. ++getxattr(2) and listxattr(2) families behave as if dirperm1 option is ++always set. Otherwise these very unpleasant situation would happen. ++- listxattr(2) may return the duplicated entries. ++- users may not be able to remove or reset the XATTR forever, ++ ++ ++XATTR/EA support in the internal (copy,move)-(up,down) ++---------------------------------------------------------------------- ++Generally the extended attributes of inode are categorized as these. ++- "security" for LSM and capability. ++- "system" for posix ACL, 'acl' mount option is required for the branch ++ fs generally. ++- "trusted" for userspace, CAP_SYS_ADMIN is required. ++- "user" for userspace, 'user_xattr' mount option is required for the ++ branch fs generally. ++ ++Moreover there are some other categories. Aufs handles these rather ++unpopular categories as the ordinary ones, ie. there is no special ++condition nor exception. ++ ++In copy-up, the support for XATTR on the dst branch may differ from the ++src branch. In this case, the copy-up operation will get an error and ++the original user operation which triggered the copy-up will fail. It ++can happen that even all copy-up will fail. ++When both of src and dst branches support XATTR and if an error occurs ++during copying XATTR, then the copy-up should fail obviously. That is a ++good reason and aufs should return an error to userspace. But when only ++the src branch support that XATTR, aufs should not return an error. ++For example, the src branch supports ACL but the dst branch doesn't ++because the dst branch may natively un-support it or temporary ++un-support it due to "noacl" mount option. Of course, the dst branch fs ++may NOT return an error even if the XATTR is not supported. It is ++totally up to the branch fs. ++ ++Anyway when the aufs internal copy-up gets an error from the dst branch ++fs, then aufs tries removing the just copied entry and returns the error ++to the userspace. The worst case of this situation will be all copy-up ++will fail. ++ ++For the copy-up operation, there two basic approaches. ++- copy the specified XATTR only (by category above), and return the ++ error unconditionally if it happens. ++- copy all XATTR, and ignore the error on the specified category only. ++ ++In order to support XATTR and to implement the correct behaviour, aufs ++chooses the latter approach and introduces some new branch attributes, ++"icexsec", "icexsys", "icextr", "icexusr", and "icexoth". ++They correspond to the XATTR namespaces (see above). Additionally, to be ++convenient, "icex" is also provided which means all "icex*" attributes ++are set (here the word "icex" stands for "ignore copy-error on XATTR"). ++ ++The meaning of these attributes is to ignore the error from setting ++XATTR on that branch. ++Note that aufs tries copying all XATTR unconditionally, and ignores the ++error from the dst branch according to the specified attributes. ++ ++Some XATTR may have its default value. The default value may come from ++the parent dir or the environment. If the default value is set at the ++file creating-time, it will be overwritten by copy-up. ++Some contradiction may happen I am afraid. ++Do we need another attribute to stop copying XATTR? I am unsure. For ++now, aufs implements the branch attributes to ignore the error. +diff -Nurp linux-5.15.37/Documentation/filesystems/aufs/design/07export.txt linux-5.15.37-aufs/Documentation/filesystems/aufs/design/07export.txt +--- linux-5.15.37/Documentation/filesystems/aufs/design/07export.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/Documentation/filesystems/aufs/design/07export.txt 2022-04-08 20:22:30.609616328 +0300 +@@ -0,0 +1,45 @@ ++ ++# Copyright (C) 2005-2021 Junjiro R. Okajima ++ ++Export Aufs via NFS ++---------------------------------------------------------------------- ++Here is an approach. ++- like xino/xib, add a new file 'xigen' which stores aufs inode ++ generation. ++- iget_locked(): initialize aufs inode generation for a new inode, and ++ store it in xigen file. ++- destroy_inode(): increment aufs inode generation and store it in xigen ++ file. it is necessary even if it is not unlinked, because any data of ++ inode may be changed by UDBA. ++- encode_fh(): for a root dir, simply return FILEID_ROOT. otherwise ++ build file handle by ++ + branch id (4 bytes) ++ + superblock generation (4 bytes) ++ + inode number (4 or 8 bytes) ++ + parent dir inode number (4 or 8 bytes) ++ + inode generation (4 bytes)) ++ + return value of exportfs_encode_fh() for the parent on a branch (4 ++ bytes) ++ + file handle for a branch (by exportfs_encode_fh()) ++- fh_to_dentry(): ++ + find the index of a branch from its id in handle, and check it is ++ still exist in aufs. ++ + 1st level: get the inode number from handle and search it in cache. ++ + 2nd level: if not found in cache, get the parent inode number from ++ the handle and search it in cache. and then open the found parent ++ dir, find the matching inode number by vfs_readdir() and get its ++ name, and call lookup_one_len() for the target dentry. ++ + 3rd level: if the parent dir is not cached, call ++ exportfs_decode_fh() for a branch and get the parent on a branch, ++ build a pathname of it, convert it a pathname in aufs, call ++ path_lookup(). now aufs gets a parent dir dentry, then handle it as ++ the 2nd level. ++ + to open the dir, aufs needs struct vfsmount. aufs keeps vfsmount ++ for every branch, but not itself. to get this, (currently) aufs ++ searches in current->nsproxy->mnt_ns list. it may not be a good ++ idea, but I didn't get other approach. ++ + test the generation of the gotten inode. ++- every inode operation: they may get EBUSY due to UDBA. in this case, ++ convert it into ESTALE for NFSD. ++- readdir(): call lockdep_on/off() because filldir in NFSD calls ++ lookup_one_len(), vfs_getattr(), encode_fh() and others. +diff -Nurp linux-5.15.37/Documentation/filesystems/aufs/design/08shwh.txt linux-5.15.37-aufs/Documentation/filesystems/aufs/design/08shwh.txt +--- linux-5.15.37/Documentation/filesystems/aufs/design/08shwh.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/Documentation/filesystems/aufs/design/08shwh.txt 2022-04-08 20:22:30.609616328 +0300 +@@ -0,0 +1,39 @@ ++ ++# Copyright (C) 2005-2021 Junjiro R. Okajima ++ ++Show Whiteout Mode (shwh) ++---------------------------------------------------------------------- ++Generally aufs hides the name of whiteouts. But in some cases, to show ++them is very useful for users. For instance, creating a new middle layer ++(branch) by merging existing layers. ++ ++(borrowing aufs1 HOW-TO from a user, Michael Towers) ++When you have three branches, ++- Bottom: 'system', squashfs (underlying base system), read-only ++- Middle: 'mods', squashfs, read-only ++- Top: 'overlay', ram (tmpfs), read-write ++ ++The top layer is loaded at boot time and saved at shutdown, to preserve ++the changes made to the system during the session. ++When larger changes have been made, or smaller changes have accumulated, ++the size of the saved top layer data grows. At this point, it would be ++nice to be able to merge the two overlay branches ('mods' and 'overlay') ++and rewrite the 'mods' squashfs, clearing the top layer and thus ++restoring save and load speed. ++ ++This merging is simplified by the use of another aufs mount, of just the ++two overlay branches using the 'shwh' option. ++# mount -t aufs -o ro,shwh,br:/livesys/overlay=ro+wh:/livesys/mods=rr+wh \ ++ aufs /livesys/merge_union ++ ++A merged view of these two branches is then available at ++/livesys/merge_union, and the new feature is that the whiteouts are ++visible! ++Note that in 'shwh' mode the aufs mount must be 'ro', which will disable ++writing to all branches. Also the default mode for all branches is 'ro'. ++It is now possible to save the combined contents of the two overlay ++branches to a new squashfs, e.g.: ++# mksquashfs /livesys/merge_union /path/to/newmods.squash ++ ++This new squashfs archive can be stored on the boot device and the ++initramfs will use it to replace the old one at the next boot. +diff -Nurp linux-5.15.37/Documentation/filesystems/aufs/design/10dynop.txt linux-5.15.37-aufs/Documentation/filesystems/aufs/design/10dynop.txt +--- linux-5.15.37/Documentation/filesystems/aufs/design/10dynop.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/Documentation/filesystems/aufs/design/10dynop.txt 2022-04-08 20:22:30.609616328 +0300 +@@ -0,0 +1,34 @@ ++ ++# Copyright (C) 2010-2021 Junjiro R. Okajima ++ ++Dynamically customizable FS operations ++---------------------------------------------------------------------- ++Generally FS operations (struct inode_operations, struct ++address_space_operations, struct file_operations, etc.) are defined as ++"static const", but it never means that FS have only one set of ++operation. Some FS have multiple sets of them. For instance, ext2 has ++three sets, one for XIP, for NOBH, and for normal. ++Since aufs overrides and redirects these operations, sometimes aufs has ++to change its behaviour according to the branch FS type. More importantly ++VFS acts differently if a function (member in the struct) is set or ++not. It means aufs should have several sets of operations and select one ++among them according to the branch FS definition. ++ ++In order to solve this problem and not to affect the behaviour of VFS, ++aufs defines these operations dynamically. For instance, aufs defines ++dummy direct_IO function for struct address_space_operations, but it may ++not be set to the address_space_operations actually. When the branch FS ++doesn't have it, aufs doesn't set it to its address_space_operations ++while the function definition itself is still alive. So the behaviour ++itself will not change, and it will return an error when direct_IO is ++not set. ++ ++The lifetime of these dynamically generated operation object is ++maintained by aufs branch object. When the branch is removed from aufs, ++the reference counter of the object is decremented. When it reaches ++zero, the dynamically generated operation object will be freed. ++ ++This approach is designed to support AIO (io_submit), Direct I/O and ++XIP (DAX) mainly. ++Currently this approach is applied to address_space_operations for ++regular files only. +diff -Nurp linux-5.15.37/Documentation/filesystems/aufs/README linux-5.15.37-aufs/Documentation/filesystems/aufs/README +--- linux-5.15.37/Documentation/filesystems/aufs/README 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/Documentation/filesystems/aufs/README 2022-04-08 20:22:30.608616279 +0300 +@@ -0,0 +1,396 @@ ++ ++Aufs5 -- advanced multi layered unification filesystem version 5.x ++http://aufs.sf.net ++Junjiro R. Okajima ++ ++ ++0. Introduction ++---------------------------------------- ++In the early days, aufs was entirely re-designed and re-implemented ++Unionfs Version 1.x series. Adding many original ideas, approaches, ++improvements and implementations, it became totally different from ++Unionfs while keeping the basic features. ++Later, Unionfs Version 2.x series began taking some of the same ++approaches to aufs1's. ++Unionfs was being developed by Professor Erez Zadok at Stony Brook ++University and his team. ++ ++Aufs5 supports linux-v5.0 and later, If you want older kernel version ++support, ++- for linux-v4.x series, try aufs4-linux.git or aufs4-standalone.git ++- for linux-v3.x series, try aufs3-linux.git or aufs3-standalone.git ++- for linux-v2.6.16 and later, try aufs2-2.6.git, aufs2-standalone.git ++ or aufs1 from CVS on SourceForge. ++ ++Note: it becomes clear that "Aufs was rejected. Let's give it up." ++ According to Christoph Hellwig, linux rejects all union-type ++ filesystems but UnionMount. ++ ++ ++PS. Al Viro seems have a plan to merge aufs as well as overlayfs and ++ UnionMount, and he pointed out an issue around a directory mutex ++ lock and aufs addressed it. But it is still unsure whether aufs will ++ be merged (or any other union solution). ++ ++ ++ ++1. Features ++---------------------------------------- ++- unite several directories into a single virtual filesystem. The member ++ directory is called as a branch. ++- you can specify the permission flags to the branch, which are 'readonly', ++ 'readwrite' and 'whiteout-able.' ++- by upper writable branch, internal copyup and whiteout, files/dirs on ++ readonly branch are modifiable logically. ++- dynamic branch manipulation, add, del. ++- etc... ++ ++Also there are many enhancements in aufs, such as: ++- test only the highest one for the directory permission (dirperm1) ++- copyup on open (coo=) ++- 'move' policy for copy-up between two writable branches, after ++ checking free space. ++- xattr, acl ++- readdir(3) in userspace. ++- keep inode number by external inode number table ++- keep the timestamps of file/dir in internal copyup operation ++- seekable directory, supporting NFS readdir. ++- whiteout is hardlinked in order to reduce the consumption of inodes ++ on branch ++- do not copyup, nor create a whiteout when it is unnecessary ++- revert a single systemcall when an error occurs in aufs ++- remount interface instead of ioctl ++- maintain /etc/mtab by an external command, /sbin/mount.aufs. ++- loopback mounted filesystem as a branch ++- kernel thread for removing the dir who has a plenty of whiteouts ++- support copyup sparse file (a file which has a 'hole' in it) ++- default permission flags for branches ++- selectable permission flags for ro branch, whether whiteout can ++ exist or not ++- export via NFS. ++- support /fs/aufs and /aufs. ++- support multiple writable branches, some policies to select one ++ among multiple writable branches. ++- a new semantics for link(2) and rename(2) to support multiple ++ writable branches. ++- no glibc changes are required. ++- pseudo hardlink (hardlink over branches) ++- allow a direct access manually to a file on branch, e.g. bypassing aufs. ++ including NFS or remote filesystem branch. ++- userspace wrapper for pathconf(3)/fpathconf(3) with _PC_LINK_MAX. ++- and more... ++ ++Currently these features are dropped temporary from aufs5. ++See design/08plan.txt in detail. ++- nested mount, i.e. aufs as readonly no-whiteout branch of another aufs ++ (robr) ++- statistics of aufs thread (/sys/fs/aufs/stat) ++ ++Features or just an idea in the future (see also design/*.txt), ++- reorder the branch index without del/re-add. ++- permanent xino files for NFSD ++- an option for refreshing the opened files after add/del branches ++- light version, without branch manipulation. (unnecessary?) ++- copyup in userspace ++- inotify in userspace ++- readv/writev ++ ++ ++2. Download ++---------------------------------------- ++There are three GIT trees for aufs5, aufs5-linux.git, ++aufs5-standalone.git, and aufs-util.git. Note that there is no "5" in ++"aufs-util.git." ++While the aufs-util is always necessary, you need either of aufs5-linux ++or aufs5-standalone. ++ ++The aufs5-linux tree includes the whole linux mainline GIT tree, ++git://git.kernel.org/.../torvalds/linux.git. ++And you cannot select CONFIG_AUFS_FS=m for this version, eg. you cannot ++build aufs5 as an external kernel module. ++Several extra patches are not included in this tree. Only ++aufs5-standalone tree contains them. They are described in the later ++section "Configuration and Compilation." ++ ++On the other hand, the aufs5-standalone tree has only aufs source files ++and necessary patches, and you can select CONFIG_AUFS_FS=m. ++But you need to apply all aufs patches manually. ++ ++You will find GIT branches whose name is in form of "aufs5.x" where "x" ++represents the linux kernel version, "linux-5.x". For instance, ++"aufs5.0" is for linux-5.0. For latest "linux-5.x-rcN", use ++"aufs5.x-rcN" branch. ++ ++o aufs5-linux tree ++$ git clone --reference /your/linux/git/tree \ ++ git://github.com/sfjro/aufs5-linux.git aufs5-linux.git ++- if you don't have linux GIT tree, then remove "--reference ..." ++$ cd aufs5-linux.git ++$ git checkout origin/aufs5.0 ++ ++Or You may want to directly git-pull aufs into your linux GIT tree, and ++leave the patch-work to GIT. ++$ cd /your/linux/git/tree ++$ git remote add aufs5 git://github.com/sfjro/aufs5-linux.git ++$ git fetch aufs5 ++$ git checkout -b my5.0 v5.0 ++$ (add your local change...) ++$ git pull aufs5 aufs5.0 ++- now you have v5.0 + your_changes + aufs5.0 in you my5.0 branch. ++- you may need to solve some conflicts between your_changes and ++ aufs5.0. in this case, git-rerere is recommended so that you can ++ solve the similar conflicts automatically when you upgrade to 5.1 or ++ later in the future. ++ ++o aufs5-standalone tree ++$ git clone git://github.com/sfjro/aufs5-standalone.git aufs5-standalone.git ++$ cd aufs5-standalone.git ++$ git checkout origin/aufs5.0 ++ ++o aufs-util tree ++$ git clone git://git.code.sf.net/p/aufs/aufs-util aufs-util.git ++- note that the public aufs-util.git is on SourceForge instead of ++ GitHUB. ++$ cd aufs-util.git ++$ git checkout origin/aufs5.0 ++ ++Note: The 5.x-rcN branch is to be used with `rc' kernel versions ONLY. ++The minor version number, 'x' in '5.x', of aufs may not always ++follow the minor version number of the kernel. ++Because changes in the kernel that cause the use of a new ++minor version number do not always require changes to aufs-util. ++ ++Since aufs-util has its own minor version number, you may not be ++able to find a GIT branch in aufs-util for your kernel's ++exact minor version number. ++In this case, you should git-checkout the branch for the ++nearest lower number. ++ ++For (an unreleased) example: ++If you are using "linux-5.10" and the "aufs5.10" branch ++does not exist in aufs-util repository, then "aufs5.9", "aufs5.8" ++or something numerically smaller is the branch for your kernel. ++ ++Also you can view all branches by ++ $ git branch -a ++ ++ ++3. Configuration and Compilation ++---------------------------------------- ++Make sure you have git-checkout'ed the correct branch. ++ ++For aufs5-linux tree, ++- enable CONFIG_AUFS_FS. ++- set other aufs configurations if necessary. ++- for aufs5.13 and later ++ Because aufs is not only an ordinary filesystem (callee of VFS), but ++ also a caller of VFS functions for branch filesystems, subclassing of ++ the internal locks for LOCKDEP is necessary. LOCKDEP is a debugging ++ feature of linux kernel. If you enable CONFIG_LOCKDEP, then you will ++ need to customize some LOCKDEP numbers. Here are what I use on my ++ test environment. ++ CONFIG_LOCKDEP_BITS=21 ++ CONFIG_LOCKDEP_CHAINS_BITS=21 ++ CONFIG_LOCKDEP_STACK_TRACE_BITS=24 ++ ++For aufs5-standalone tree, ++There are several ways to build. ++ ++1. ++- apply ./aufs5-kbuild.patch to your kernel source files. ++- apply ./aufs5-base.patch too. ++- apply ./aufs5-mmap.patch too. ++- apply ./aufs5-standalone.patch too, if you have a plan to set ++ CONFIG_AUFS_FS=m. otherwise you don't need ./aufs5-standalone.patch. ++- copy ./{Documentation,fs,include/uapi/linux/aufs_type.h} files to your ++ kernel source tree. Never copy $PWD/include/uapi/linux/Kbuild. ++- enable CONFIG_AUFS_FS, you can select either ++ =m or =y. ++- and build your kernel as usual. ++- install the built kernel. ++- install the header files too by "make headers_install" to the ++ directory where you specify. By default, it is $PWD/usr. ++ "make help" shows a brief note for headers_install. ++- and reboot your system. ++ ++2. ++- module only (CONFIG_AUFS_FS=m). ++- apply ./aufs5-base.patch to your kernel source files. ++- apply ./aufs5-mmap.patch too. ++- apply ./aufs5-standalone.patch too. ++- build your kernel, don't forget "make headers_install", and reboot. ++- edit ./config.mk and set other aufs configurations if necessary. ++ Note: You should read $PWD/fs/aufs/Kconfig carefully which describes ++ every aufs configurations. ++- build the module by simple "make". ++- you can specify ${KDIR} make variable which points to your kernel ++ source tree. ++- install the files ++ + run "make install" to install the aufs module, or copy the built ++ $PWD/aufs.ko to /lib/modules/... and run depmod -a (or reboot simply). ++ + run "make install_headers" (instead of headers_install) to install ++ the modified aufs header file (you can specify DESTDIR which is ++ available in aufs standalone version's Makefile only), or copy ++ $PWD/usr/include/linux/aufs_type.h to /usr/include/linux or wherever ++ you like manually. By default, the target directory is $PWD/usr. ++- no need to apply aufs5-kbuild.patch, nor copying source files to your ++ kernel source tree. ++ ++Note: The header file aufs_type.h is necessary to build aufs-util ++ as well as "make headers_install" in the kernel source tree. ++ headers_install is subject to be forgotten, but it is essentially ++ necessary, not only for building aufs-util. ++ You may not meet problems without headers_install in some older ++ version though. ++ ++And then, ++- read README in aufs-util, build and install it ++- note that your distribution may contain an obsoleted version of ++ aufs_type.h in /usr/include/linux or something. When you build aufs ++ utilities, make sure that your compiler refers the correct aufs header ++ file which is built by "make headers_install." ++- if you want to use readdir(3) in userspace or pathconf(3) wrapper, ++ then run "make install_ulib" too. And refer to the aufs manual in ++ detail. ++ ++There several other patches in aufs5-standalone.git. They are all ++optional. When you meet some problems, they will help you. ++- aufs5-loopback.patch ++ Supports a nested loopback mount in a branch-fs. This patch is ++ unnecessary until aufs produces a message like "you may want to try ++ another patch for loopback file". ++- vfs-ino.patch ++ Modifies a system global kernel internal function get_next_ino() in ++ order to stop assigning 0 for an inode-number. Not directly related to ++ aufs, but recommended generally. ++- tmpfs-idr.patch ++ Keeps the tmpfs inode number as the lowest value. Effective to reduce ++ the size of aufs XINO files for tmpfs branch. Also it prevents the ++ duplication of inode number, which is important for backup tools and ++ other utilities. When you find aufs XINO files for tmpfs branch ++ growing too much, try this patch. ++ ++ ++4. Usage ++---------------------------------------- ++At first, make sure aufs-util are installed, and please read the aufs ++manual, aufs.5 in aufs-util.git tree. ++$ man -l aufs.5 ++ ++And then, ++$ mkdir /tmp/rw /tmp/aufs ++# mount -t aufs -o br=/tmp/rw:${HOME} none /tmp/aufs ++ ++Here is another example. The result is equivalent. ++# mount -t aufs -o br=/tmp/rw=rw:${HOME}=ro none /tmp/aufs ++ Or ++# mount -t aufs -o br:/tmp/rw none /tmp/aufs ++# mount -o remount,append:${HOME} /tmp/aufs ++ ++Then, you can see whole tree of your home dir through /tmp/aufs. If ++you modify a file under /tmp/aufs, the one on your home directory is ++not affected, instead the same named file will be newly created under ++/tmp/rw. And all of your modification to a file will be applied to ++the one under /tmp/rw. This is called the file based Copy on Write ++(COW) method. ++Aufs mount options are described in aufs.5. ++If you run chroot or something and make your aufs as a root directory, ++then you need to customize the shutdown script. See the aufs manual in ++detail. ++ ++Additionally, there are some sample usages of aufs which are a ++diskless system with network booting, and LiveCD over NFS. ++See sample dir in CVS tree on SourceForge. ++ ++ ++5. Contact ++---------------------------------------- ++When you have any problems or strange behaviour in aufs, please let me ++know with: ++- /proc/mounts (instead of the output of mount(8)) ++- /sys/module/aufs/* ++- /sys/fs/aufs/* (if you have them) ++- /debug/aufs/* (if you have them) ++- linux kernel version ++ if your kernel is not plain, for example modified by distributor, ++ the url where i can download its source is necessary too. ++- aufs version which was printed at loading the module or booting the ++ system, instead of the date you downloaded. ++- configuration (define/undefine CONFIG_AUFS_xxx) ++- kernel configuration or /proc/config.gz (if you have it) ++- LSM (linux security module, if you are using) ++- behaviour which you think to be incorrect ++- actual operation, reproducible one is better ++- mailto: aufs-users at lists.sourceforge.net ++ ++Usually, I don't watch the Public Areas(Bugs, Support Requests, Patches, ++and Feature Requests) on SourceForge. Please join and write to ++aufs-users ML. ++ ++ ++6. Acknowledgements ++---------------------------------------- ++Thanks to everyone who have tried and are using aufs, whoever ++have reported a bug or any feedback. ++ ++Especially donators: ++Tomas Matejicek(slax.org) made a donation (much more than once). ++ Since Apr 2010, Tomas M (the author of Slax and Linux Live ++ scripts) is making "doubling" donations. ++ Unfortunately I cannot list all of the donators, but I really ++ appreciate. ++ It ends Aug 2010, but the ordinary donation URL is still available. ++ ++Dai Itasaka made a donation (2007/8). ++Chuck Smith made a donation (2008/4, 10 and 12). ++Henk Schoneveld made a donation (2008/9). ++Chih-Wei Huang, ASUS, CTC donated Eee PC 4G (2008/10). ++Francois Dupoux made a donation (2008/11). ++Bruno Cesar Ribas and Luis Carlos Erpen de Bona, C3SL serves public ++ aufs2 GIT tree (2009/2). ++William Grant made a donation (2009/3). ++Patrick Lane made a donation (2009/4). ++The Mail Archive (mail-archive.com) made donations (2009/5). ++Nippy Networks (Ed Wildgoose) made a donation (2009/7). ++New Dream Network, LLC (www.dreamhost.com) made a donation (2009/11). ++Pavel Pronskiy made a donation (2011/2). ++Iridium and Inmarsat satellite phone retailer (www.mailasail.com), Nippy ++ Networks (Ed Wildgoose) made a donation for hardware (2011/3). ++Max Lekomcev (DOM-TV project) made a donation (2011/7, 12, 2012/3, 6 and ++11). ++Sam Liddicott made a donation (2011/9). ++Era Scarecrow made a donation (2013/4). ++Bor Ratajc made a donation (2013/4). ++Alessandro Gorreta made a donation (2013/4). ++POIRETTE Marc made a donation (2013/4). ++Alessandro Gorreta made a donation (2013/4). ++lauri kasvandik made a donation (2013/5). ++"pemasu from Finland" made a donation (2013/7). ++The Parted Magic Project made a donation (2013/9 and 11). ++Pavel Barta made a donation (2013/10). ++Nikolay Pertsev made a donation (2014/5). ++James B made a donation (2014/7, 2015/7, and 2021/12). ++Stefano Di Biase made a donation (2014/8). ++Daniel Epellei made a donation (2015/1). ++OmegaPhil made a donation (2016/1, 2018/4). ++Tomasz Szewczyk made a donation (2016/4). ++James Burry made a donation (2016/12). ++Carsten Rose made a donation (2018/9). ++Porteus Kiosk made a donation (2018/10). ++ ++Thank you very much. ++Donations are always, including future donations, very important and ++helpful for me to keep on developing aufs. ++ ++ ++7. ++---------------------------------------- ++If you are an experienced user, no explanation is needed. Aufs is ++just a linux filesystem. ++ ++ ++Enjoy! ++ ++# Local variables: ; ++# mode: text; ++# End: ; +diff -Nurp linux-5.15.37/drivers/block/loop.c linux-5.15.37-aufs/drivers/block/loop.c +--- linux-5.15.37/drivers/block/loop.c 2022-04-08 20:07:30.626495709 +0300 ++++ linux-5.15.37-aufs/drivers/block/loop.c 2022-04-08 20:22:30.610616377 +0300 +@@ -636,6 +636,24 @@ out_putf: + return error; + } + ++/* ++ * for AUFS ++ * no get/put for file. ++ */ ++struct file *loop_backing_file(struct super_block *sb) ++{ ++ struct file *ret; ++ struct loop_device *l; ++ ++ ret = NULL; ++ if (MAJOR(sb->s_dev) == LOOP_MAJOR) { ++ l = sb->s_bdev->bd_disk->private_data; ++ ret = l->lo_backing_file; ++ } ++ return ret; ++} ++EXPORT_SYMBOL_GPL(loop_backing_file); ++ + /* loop sysfs attributes */ + + static ssize_t loop_attr_show(struct device *dev, char *page, +diff -Nurp linux-5.15.37/fs/aufs/aufs.h linux-5.15.37-aufs/fs/aufs/aufs.h +--- linux-5.15.37/fs/aufs/aufs.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/aufs.h 2022-04-08 20:22:30.611616426 +0300 +@@ -0,0 +1,49 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * all header files ++ */ ++ ++#ifndef __AUFS_H__ ++#define __AUFS_H__ ++ ++#ifdef __KERNEL__ ++ ++#define AuStub(type, name, body, ...) \ ++ static inline type name(__VA_ARGS__) { body; } ++ ++#define AuStubVoid(name, ...) \ ++ AuStub(void, name, , __VA_ARGS__) ++#define AuStubInt0(name, ...) \ ++ AuStub(int, name, return 0, __VA_ARGS__) ++ ++#include "debug.h" ++ ++#include "branch.h" ++#include "cpup.h" ++#include "dcsub.h" ++#include "dbgaufs.h" ++#include "dentry.h" ++#include "dir.h" ++#include "dirren.h" ++#include "dynop.h" ++#include "file.h" ++#include "fstype.h" ++#include "hbl.h" ++#include "inode.h" ++#include "lcnt.h" ++#include "loop.h" ++#include "module.h" ++#include "opts.h" ++#include "rwsem.h" ++#include "super.h" ++#include "sysaufs.h" ++#include "vfsub.h" ++#include "whout.h" ++#include "wkq.h" ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_H__ */ +diff -Nurp linux-5.15.37/fs/aufs/branch.c linux-5.15.37-aufs/fs/aufs/branch.c +--- linux-5.15.37/fs/aufs/branch.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/branch.c 2022-04-08 20:22:30.611616426 +0300 +@@ -0,0 +1,1414 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * branch management ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++/* ++ * free a single branch ++ */ ++static void au_br_do_free(struct au_branch *br) ++{ ++ int i; ++ struct au_wbr *wbr; ++ struct au_dykey **key; ++ ++ au_hnotify_fin_br(br); ++ /* always, regardless the mount option */ ++ au_dr_hino_free(&br->br_dirren); ++ au_xino_put(br); ++ ++ AuLCntZero(au_lcnt_read(&br->br_nfiles, /*do_rev*/0)); ++ au_lcnt_fin(&br->br_nfiles, /*do_sync*/0); ++ AuLCntZero(au_lcnt_read(&br->br_count, /*do_rev*/0)); ++ au_lcnt_fin(&br->br_count, /*do_sync*/0); ++ ++ wbr = br->br_wbr; ++ if (wbr) { ++ for (i = 0; i < AuBrWh_Last; i++) ++ dput(wbr->wbr_wh[i]); ++ AuDebugOn(atomic_read(&wbr->wbr_wh_running)); ++ AuRwDestroy(&wbr->wbr_wh_rwsem); ++ } ++ ++ if (br->br_fhsm) { ++ au_br_fhsm_fin(br->br_fhsm); ++ au_kfree_try_rcu(br->br_fhsm); ++ } ++ ++ key = br->br_dykey; ++ for (i = 0; i < AuBrDynOp; i++, key++) ++ if (*key) ++ au_dy_put(*key); ++ else ++ break; ++ ++ /* recursive lock, s_umount of branch's */ ++ /* synchronize_rcu(); */ /* why? */ ++ lockdep_off(); ++ path_put(&br->br_path); ++ lockdep_on(); ++ au_kfree_rcu(wbr); ++ au_lcnt_wait_for_fin(&br->br_nfiles); ++ au_lcnt_wait_for_fin(&br->br_count); ++ /* I don't know why, but percpu_refcount requires this */ ++ /* synchronize_rcu(); */ ++ au_kfree_rcu(br); ++} ++ ++/* ++ * frees all branches ++ */ ++void au_br_free(struct au_sbinfo *sbinfo) ++{ ++ aufs_bindex_t bmax; ++ struct au_branch **br; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ bmax = sbinfo->si_bbot + 1; ++ br = sbinfo->si_branch; ++ while (bmax--) ++ au_br_do_free(*br++); ++} ++ ++/* ++ * find the index of a branch which is specified by @br_id. ++ */ ++int au_br_index(struct super_block *sb, aufs_bindex_t br_id) ++{ ++ aufs_bindex_t bindex, bbot; ++ ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) ++ if (au_sbr_id(sb, bindex) == br_id) ++ return bindex; ++ return -1; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * add a branch ++ */ ++ ++static int test_overlap(struct super_block *sb, struct dentry *h_adding, ++ struct dentry *h_root) ++{ ++ if (unlikely(h_adding == h_root ++ || au_test_loopback_overlap(sb, h_adding))) ++ return 1; ++ if (h_adding->d_sb != h_root->d_sb) ++ return 0; ++ return au_test_subdir(h_adding, h_root) ++ || au_test_subdir(h_root, h_adding); ++} ++ ++/* ++ * returns a newly allocated branch. @new_nbranch is a number of branches ++ * after adding a branch. ++ */ ++static struct au_branch *au_br_alloc(struct super_block *sb, int new_nbranch, ++ int perm) ++{ ++ struct au_branch *add_branch; ++ struct dentry *root; ++ struct inode *inode; ++ int err; ++ ++ err = -ENOMEM; ++ add_branch = kzalloc(sizeof(*add_branch), GFP_NOFS); ++ if (unlikely(!add_branch)) ++ goto out; ++ add_branch->br_xino = au_xino_alloc(/*nfile*/1); ++ if (unlikely(!add_branch->br_xino)) ++ goto out_br; ++ err = au_hnotify_init_br(add_branch, perm); ++ if (unlikely(err)) ++ goto out_xino; ++ ++ if (au_br_writable(perm)) { ++ /* may be freed separately at changing the branch permission */ ++ add_branch->br_wbr = kzalloc(sizeof(*add_branch->br_wbr), ++ GFP_NOFS); ++ if (unlikely(!add_branch->br_wbr)) ++ goto out_hnotify; ++ } ++ ++ if (au_br_fhsm(perm)) { ++ err = au_fhsm_br_alloc(add_branch); ++ if (unlikely(err)) ++ goto out_wbr; ++ } ++ ++ root = sb->s_root; ++ err = au_sbr_realloc(au_sbi(sb), new_nbranch, /*may_shrink*/0); ++ if (!err) ++ err = au_di_realloc(au_di(root), new_nbranch, /*may_shrink*/0); ++ if (!err) { ++ inode = d_inode(root); ++ err = au_hinode_realloc(au_ii(inode), new_nbranch, ++ /*may_shrink*/0); ++ } ++ if (!err) ++ return add_branch; /* success */ ++ ++out_wbr: ++ au_kfree_rcu(add_branch->br_wbr); ++out_hnotify: ++ au_hnotify_fin_br(add_branch); ++out_xino: ++ au_xino_put(add_branch); ++out_br: ++ au_kfree_rcu(add_branch); ++out: ++ return ERR_PTR(err); ++} ++ ++/* ++ * test if the branch permission is legal or not. ++ */ ++static int test_br(struct inode *inode, int brperm, char *path) ++{ ++ int err; ++ ++ err = (au_br_writable(brperm) && IS_RDONLY(inode)); ++ if (!err) ++ goto out; ++ ++ err = -EINVAL; ++ pr_err("write permission for readonly mount or inode, %s\n", path); ++ ++out: ++ return err; ++} ++ ++/* ++ * returns: ++ * 0: success, the caller will add it ++ * plus: success, it is already unified, the caller should ignore it ++ * minus: error ++ */ ++static int test_add(struct super_block *sb, struct au_opt_add *add, int remount) ++{ ++ int err; ++ aufs_bindex_t bbot, bindex; ++ struct dentry *root, *h_dentry; ++ struct inode *inode, *h_inode; ++ ++ root = sb->s_root; ++ bbot = au_sbbot(sb); ++ if (unlikely(bbot >= 0 ++ && au_find_dbindex(root, add->path.dentry) >= 0)) { ++ err = 1; ++ if (!remount) { ++ err = -EINVAL; ++ pr_err("%s duplicated\n", add->pathname); ++ } ++ goto out; ++ } ++ ++ err = -ENOSPC; /* -E2BIG; */ ++ if (unlikely(AUFS_BRANCH_MAX <= add->bindex ++ || AUFS_BRANCH_MAX - 1 <= bbot)) { ++ pr_err("number of branches exceeded %s\n", add->pathname); ++ goto out; ++ } ++ ++ err = -EDOM; ++ if (unlikely(add->bindex < 0 || bbot + 1 < add->bindex)) { ++ pr_err("bad index %d\n", add->bindex); ++ goto out; ++ } ++ ++ inode = d_inode(add->path.dentry); ++ err = -ENOENT; ++ if (unlikely(!inode->i_nlink)) { ++ pr_err("no existence %s\n", add->pathname); ++ goto out; ++ } ++ ++ err = -EINVAL; ++ if (unlikely(inode->i_sb == sb)) { ++ pr_err("%s must be outside\n", add->pathname); ++ goto out; ++ } ++ ++ if (unlikely(au_test_fs_unsuppoted(inode->i_sb))) { ++ pr_err("unsupported filesystem, %s (%s)\n", ++ add->pathname, au_sbtype(inode->i_sb)); ++ goto out; ++ } ++ ++ if (unlikely(inode->i_sb->s_stack_depth)) { ++ pr_err("already stacked, %s (%s)\n", ++ add->pathname, au_sbtype(inode->i_sb)); ++ goto out; ++ } ++ ++ err = test_br(d_inode(add->path.dentry), add->perm, add->pathname); ++ if (unlikely(err)) ++ goto out; ++ ++ if (bbot < 0) ++ return 0; /* success */ ++ ++ err = -EINVAL; ++ for (bindex = 0; bindex <= bbot; bindex++) ++ if (unlikely(test_overlap(sb, add->path.dentry, ++ au_h_dptr(root, bindex)))) { ++ pr_err("%s is overlapped\n", add->pathname); ++ goto out; ++ } ++ ++ err = 0; ++ if (au_opt_test(au_mntflags(sb), WARN_PERM)) { ++ h_dentry = au_h_dptr(root, 0); ++ h_inode = d_inode(h_dentry); ++ if ((h_inode->i_mode & S_IALLUGO) != (inode->i_mode & S_IALLUGO) ++ || !uid_eq(h_inode->i_uid, inode->i_uid) ++ || !gid_eq(h_inode->i_gid, inode->i_gid)) ++ pr_warn("uid/gid/perm %s %u/%u/0%o, %u/%u/0%o\n", ++ add->pathname, ++ i_uid_read(inode), i_gid_read(inode), ++ (inode->i_mode & S_IALLUGO), ++ i_uid_read(h_inode), i_gid_read(h_inode), ++ (h_inode->i_mode & S_IALLUGO)); ++ } ++ ++out: ++ return err; ++} ++ ++/* ++ * initialize or clean the whiteouts for an adding branch ++ */ ++static int au_br_init_wh(struct super_block *sb, struct au_branch *br, ++ int new_perm) ++{ ++ int err, old_perm; ++ aufs_bindex_t bindex; ++ struct inode *h_inode; ++ struct au_wbr *wbr; ++ struct au_hinode *hdir; ++ struct dentry *h_dentry; ++ ++ err = vfsub_mnt_want_write(au_br_mnt(br)); ++ if (unlikely(err)) ++ goto out; ++ ++ wbr = br->br_wbr; ++ old_perm = br->br_perm; ++ br->br_perm = new_perm; ++ hdir = NULL; ++ h_inode = NULL; ++ bindex = au_br_index(sb, br->br_id); ++ if (0 <= bindex) { ++ hdir = au_hi(d_inode(sb->s_root), bindex); ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ } else { ++ h_dentry = au_br_dentry(br); ++ h_inode = d_inode(h_dentry); ++ inode_lock_nested(h_inode, AuLsc_I_PARENT); ++ } ++ if (!wbr) ++ err = au_wh_init(br, sb); ++ else { ++ wbr_wh_write_lock(wbr); ++ err = au_wh_init(br, sb); ++ wbr_wh_write_unlock(wbr); ++ } ++ if (hdir) ++ au_hn_inode_unlock(hdir); ++ else ++ inode_unlock(h_inode); ++ vfsub_mnt_drop_write(au_br_mnt(br)); ++ br->br_perm = old_perm; ++ ++ if (!err && wbr && !au_br_writable(new_perm)) { ++ au_kfree_rcu(wbr); ++ br->br_wbr = NULL; ++ } ++ ++out: ++ return err; ++} ++ ++static int au_wbr_init(struct au_branch *br, struct super_block *sb, ++ int perm) ++{ ++ int err; ++ struct kstatfs kst; ++ struct au_wbr *wbr; ++ ++ wbr = br->br_wbr; ++ au_rw_init(&wbr->wbr_wh_rwsem); ++ atomic_set(&wbr->wbr_wh_running, 0); ++ ++ /* ++ * a limit for rmdir/rename a dir ++ * cf. AUFS_MAX_NAMELEN in include/uapi/linux/aufs_type.h ++ */ ++ err = vfs_statfs(&br->br_path, &kst); ++ if (unlikely(err)) ++ goto out; ++ err = -EINVAL; ++ if (kst.f_namelen >= NAME_MAX) ++ err = au_br_init_wh(sb, br, perm); ++ else ++ pr_err("%pd(%s), unsupported namelen %ld\n", ++ au_br_dentry(br), ++ au_sbtype(au_br_dentry(br)->d_sb), kst.f_namelen); ++ ++out: ++ return err; ++} ++ ++/* initialize a new branch */ ++static int au_br_init(struct au_branch *br, struct super_block *sb, ++ struct au_opt_add *add) ++{ ++ int err; ++ struct au_branch *brbase; ++ struct file *xf; ++ struct inode *h_inode; ++ ++ err = 0; ++ br->br_perm = add->perm; ++ br->br_path = add->path; /* set first, path_get() later */ ++ spin_lock_init(&br->br_dykey_lock); ++ au_lcnt_init(&br->br_nfiles, /*release*/NULL); ++ au_lcnt_init(&br->br_count, /*release*/NULL); ++ br->br_id = au_new_br_id(sb); ++ AuDebugOn(br->br_id < 0); ++ ++ /* always, regardless the given option */ ++ err = au_dr_br_init(sb, br, &add->path); ++ if (unlikely(err)) ++ goto out_err; ++ ++ if (au_br_writable(add->perm)) { ++ err = au_wbr_init(br, sb, add->perm); ++ if (unlikely(err)) ++ goto out_err; ++ } ++ ++ if (au_opt_test(au_mntflags(sb), XINO)) { ++ brbase = au_sbr(sb, 0); ++ xf = au_xino_file(brbase->br_xino, /*idx*/-1); ++ AuDebugOn(!xf); ++ h_inode = d_inode(add->path.dentry); ++ err = au_xino_init_br(sb, br, h_inode->i_ino, &xf->f_path); ++ if (unlikely(err)) { ++ AuDebugOn(au_xino_file(br->br_xino, /*idx*/-1)); ++ goto out_err; ++ } ++ } ++ ++ sysaufs_br_init(br); ++ path_get(&br->br_path); ++ goto out; /* success */ ++ ++out_err: ++ memset(&br->br_path, 0, sizeof(br->br_path)); ++out: ++ return err; ++} ++ ++static void au_br_do_add_brp(struct au_sbinfo *sbinfo, aufs_bindex_t bindex, ++ struct au_branch *br, aufs_bindex_t bbot, ++ aufs_bindex_t amount) ++{ ++ struct au_branch **brp; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ brp = sbinfo->si_branch + bindex; ++ memmove(brp + 1, brp, sizeof(*brp) * amount); ++ *brp = br; ++ sbinfo->si_bbot++; ++ if (unlikely(bbot < 0)) ++ sbinfo->si_bbot = 0; ++} ++ ++static void au_br_do_add_hdp(struct au_dinfo *dinfo, aufs_bindex_t bindex, ++ aufs_bindex_t bbot, aufs_bindex_t amount) ++{ ++ struct au_hdentry *hdp; ++ ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ hdp = au_hdentry(dinfo, bindex); ++ memmove(hdp + 1, hdp, sizeof(*hdp) * amount); ++ au_h_dentry_init(hdp); ++ dinfo->di_bbot++; ++ if (unlikely(bbot < 0)) ++ dinfo->di_btop = 0; ++} ++ ++static void au_br_do_add_hip(struct au_iinfo *iinfo, aufs_bindex_t bindex, ++ aufs_bindex_t bbot, aufs_bindex_t amount) ++{ ++ struct au_hinode *hip; ++ ++ AuRwMustWriteLock(&iinfo->ii_rwsem); ++ ++ hip = au_hinode(iinfo, bindex); ++ memmove(hip + 1, hip, sizeof(*hip) * amount); ++ au_hinode_init(hip); ++ iinfo->ii_bbot++; ++ if (unlikely(bbot < 0)) ++ iinfo->ii_btop = 0; ++} ++ ++static void au_br_do_add(struct super_block *sb, struct au_branch *br, ++ aufs_bindex_t bindex) ++{ ++ struct dentry *root, *h_dentry; ++ struct inode *root_inode, *h_inode; ++ aufs_bindex_t bbot, amount; ++ ++ root = sb->s_root; ++ root_inode = d_inode(root); ++ bbot = au_sbbot(sb); ++ amount = bbot + 1 - bindex; ++ h_dentry = au_br_dentry(br); ++ au_sbilist_lock(); ++ au_br_do_add_brp(au_sbi(sb), bindex, br, bbot, amount); ++ au_br_do_add_hdp(au_di(root), bindex, bbot, amount); ++ au_br_do_add_hip(au_ii(root_inode), bindex, bbot, amount); ++ au_set_h_dptr(root, bindex, dget(h_dentry)); ++ h_inode = d_inode(h_dentry); ++ au_set_h_iptr(root_inode, bindex, au_igrab(h_inode), /*flags*/0); ++ au_sbilist_unlock(); ++} ++ ++int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount) ++{ ++ int err; ++ aufs_bindex_t bbot, add_bindex; ++ struct dentry *root, *h_dentry; ++ struct inode *root_inode; ++ struct au_branch *add_branch; ++ ++ root = sb->s_root; ++ root_inode = d_inode(root); ++ IMustLock(root_inode); ++ IiMustWriteLock(root_inode); ++ err = test_add(sb, add, remount); ++ if (unlikely(err < 0)) ++ goto out; ++ if (err) { ++ err = 0; ++ goto out; /* success */ ++ } ++ ++ bbot = au_sbbot(sb); ++ add_branch = au_br_alloc(sb, bbot + 2, add->perm); ++ err = PTR_ERR(add_branch); ++ if (IS_ERR(add_branch)) ++ goto out; ++ ++ err = au_br_init(add_branch, sb, add); ++ if (unlikely(err)) { ++ au_br_do_free(add_branch); ++ goto out; ++ } ++ ++ add_bindex = add->bindex; ++ sysaufs_brs_del(sb, add_bindex); /* remove successors */ ++ au_br_do_add(sb, add_branch, add_bindex); ++ sysaufs_brs_add(sb, add_bindex); /* append successors */ ++ dbgaufs_brs_add(sb, add_bindex, /*topdown*/0); /* rename successors */ ++ ++ h_dentry = add->path.dentry; ++ if (!add_bindex) { ++ au_cpup_attr_all(root_inode, /*force*/1); ++ sb->s_maxbytes = h_dentry->d_sb->s_maxbytes; ++ } else ++ au_add_nlink(root_inode, d_inode(h_dentry)); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static unsigned long long au_farray_cb(struct super_block *sb, void *a, ++ unsigned long long max __maybe_unused, ++ void *arg) ++{ ++ unsigned long long n; ++ struct file **p, *f; ++ struct hlist_bl_head *files; ++ struct hlist_bl_node *pos; ++ struct au_finfo *finfo; ++ ++ n = 0; ++ p = a; ++ files = &au_sbi(sb)->si_files; ++ hlist_bl_lock(files); ++ hlist_bl_for_each_entry(finfo, pos, files, fi_hlist) { ++ f = finfo->fi_file; ++ if (file_count(f) ++ && !special_file(file_inode(f)->i_mode)) { ++ get_file(f); ++ *p++ = f; ++ n++; ++ AuDebugOn(n > max); ++ } ++ } ++ hlist_bl_unlock(files); ++ ++ return n; ++} ++ ++static struct file **au_farray_alloc(struct super_block *sb, ++ unsigned long long *max) ++{ ++ struct au_sbinfo *sbi; ++ ++ sbi = au_sbi(sb); ++ *max = au_lcnt_read(&sbi->si_nfiles, /*do_rev*/1); ++ return au_array_alloc(max, au_farray_cb, sb, /*arg*/NULL); ++} ++ ++static void au_farray_free(struct file **a, unsigned long long max) ++{ ++ unsigned long long ull; ++ ++ for (ull = 0; ull < max; ull++) ++ if (a[ull]) ++ fput(a[ull]); ++ kvfree(a); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * delete a branch ++ */ ++ ++/* to show the line number, do not make it inlined function */ ++#define AuVerbose(do_info, fmt, ...) do { \ ++ if (do_info) \ ++ pr_info(fmt, ##__VA_ARGS__); \ ++} while (0) ++ ++static int au_test_ibusy(struct inode *inode, aufs_bindex_t btop, ++ aufs_bindex_t bbot) ++{ ++ return (inode && !S_ISDIR(inode->i_mode)) || btop == bbot; ++} ++ ++static int au_test_dbusy(struct dentry *dentry, aufs_bindex_t btop, ++ aufs_bindex_t bbot) ++{ ++ return au_test_ibusy(d_inode(dentry), btop, bbot); ++} ++ ++/* ++ * test if the branch is deletable or not. ++ */ ++static int test_dentry_busy(struct dentry *root, aufs_bindex_t bindex, ++ unsigned int sigen, const unsigned int verbose) ++{ ++ int err, i, j, ndentry; ++ aufs_bindex_t btop, bbot; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry *d; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, root, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ for (i = 0; !err && i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ ndentry = dpage->ndentry; ++ for (j = 0; !err && j < ndentry; j++) { ++ d = dpage->dentries[j]; ++ AuDebugOn(au_dcount(d) <= 0); ++ if (!au_digen_test(d, sigen)) { ++ di_read_lock_child(d, AuLock_IR); ++ if (unlikely(au_dbrange_test(d))) { ++ di_read_unlock(d, AuLock_IR); ++ continue; ++ } ++ } else { ++ di_write_lock_child(d); ++ if (unlikely(au_dbrange_test(d))) { ++ di_write_unlock(d); ++ continue; ++ } ++ err = au_reval_dpath(d, sigen); ++ if (!err) ++ di_downgrade_lock(d, AuLock_IR); ++ else { ++ di_write_unlock(d); ++ break; ++ } ++ } ++ ++ /* AuDbgDentry(d); */ ++ btop = au_dbtop(d); ++ bbot = au_dbbot(d); ++ if (btop <= bindex ++ && bindex <= bbot ++ && au_h_dptr(d, bindex) ++ && au_test_dbusy(d, btop, bbot)) { ++ err = -EBUSY; ++ AuVerbose(verbose, "busy %pd\n", d); ++ AuDbgDentry(d); ++ } ++ di_read_unlock(d, AuLock_IR); ++ } ++ } ++ ++out_dpages: ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++static int test_inode_busy(struct super_block *sb, aufs_bindex_t bindex, ++ unsigned int sigen, const unsigned int verbose) ++{ ++ int err; ++ unsigned long long max, ull; ++ struct inode *i, **array; ++ aufs_bindex_t btop, bbot; ++ ++ array = au_iarray_alloc(sb, &max); ++ err = PTR_ERR(array); ++ if (IS_ERR(array)) ++ goto out; ++ ++ err = 0; ++ AuDbg("b%d\n", bindex); ++ for (ull = 0; !err && ull < max; ull++) { ++ i = array[ull]; ++ if (unlikely(!i)) ++ break; ++ if (i->i_ino == AUFS_ROOT_INO) ++ continue; ++ ++ /* AuDbgInode(i); */ ++ if (au_iigen(i, NULL) == sigen) ++ ii_read_lock_child(i); ++ else { ++ ii_write_lock_child(i); ++ err = au_refresh_hinode_self(i); ++ au_iigen_dec(i); ++ if (!err) ++ ii_downgrade_lock(i); ++ else { ++ ii_write_unlock(i); ++ break; ++ } ++ } ++ ++ btop = au_ibtop(i); ++ bbot = au_ibbot(i); ++ if (btop <= bindex ++ && bindex <= bbot ++ && au_h_iptr(i, bindex) ++ && au_test_ibusy(i, btop, bbot)) { ++ err = -EBUSY; ++ AuVerbose(verbose, "busy i%lu\n", i->i_ino); ++ AuDbgInode(i); ++ } ++ ii_read_unlock(i); ++ } ++ au_iarray_free(array, max); ++ ++out: ++ return err; ++} ++ ++static int test_children_busy(struct dentry *root, aufs_bindex_t bindex, ++ const unsigned int verbose) ++{ ++ int err; ++ unsigned int sigen; ++ ++ sigen = au_sigen(root->d_sb); ++ DiMustNoWaiters(root); ++ IiMustNoWaiters(d_inode(root)); ++ di_write_unlock(root); ++ err = test_dentry_busy(root, bindex, sigen, verbose); ++ if (!err) ++ err = test_inode_busy(root->d_sb, bindex, sigen, verbose); ++ di_write_lock_child(root); /* aufs_write_lock() calls ..._child() */ ++ ++ return err; ++} ++ ++static int test_dir_busy(struct file *file, aufs_bindex_t br_id, ++ struct file **to_free, int *idx) ++{ ++ int err; ++ unsigned char matched, root; ++ aufs_bindex_t bindex, bbot; ++ struct au_fidir *fidir; ++ struct au_hfile *hfile; ++ ++ err = 0; ++ root = IS_ROOT(file->f_path.dentry); ++ if (root) { ++ get_file(file); ++ to_free[*idx] = file; ++ (*idx)++; ++ goto out; ++ } ++ ++ matched = 0; ++ fidir = au_fi(file)->fi_hdir; ++ AuDebugOn(!fidir); ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); bindex <= bbot; bindex++) { ++ hfile = fidir->fd_hfile + bindex; ++ if (!hfile->hf_file) ++ continue; ++ ++ if (hfile->hf_br->br_id == br_id) { ++ matched = 1; ++ break; ++ } ++ } ++ if (matched) ++ err = -EBUSY; ++ ++out: ++ return err; ++} ++ ++static int test_file_busy(struct super_block *sb, aufs_bindex_t br_id, ++ struct file **to_free, int opened) ++{ ++ int err, idx; ++ unsigned long long ull, max; ++ aufs_bindex_t btop; ++ struct file *file, **array; ++ struct dentry *root; ++ struct au_hfile *hfile; ++ ++ array = au_farray_alloc(sb, &max); ++ err = PTR_ERR(array); ++ if (IS_ERR(array)) ++ goto out; ++ ++ err = 0; ++ idx = 0; ++ root = sb->s_root; ++ di_write_unlock(root); ++ for (ull = 0; ull < max; ull++) { ++ file = array[ull]; ++ if (unlikely(!file)) ++ break; ++ ++ /* AuDbg("%pD\n", file); */ ++ fi_read_lock(file); ++ btop = au_fbtop(file); ++ if (!d_is_dir(file->f_path.dentry)) { ++ hfile = &au_fi(file)->fi_htop; ++ if (hfile->hf_br->br_id == br_id) ++ err = -EBUSY; ++ } else ++ err = test_dir_busy(file, br_id, to_free, &idx); ++ fi_read_unlock(file); ++ if (unlikely(err)) ++ break; ++ } ++ di_write_lock_child(root); ++ au_farray_free(array, max); ++ AuDebugOn(idx > opened); ++ ++out: ++ return err; ++} ++ ++static void br_del_file(struct file **to_free, unsigned long long opened, ++ aufs_bindex_t br_id) ++{ ++ unsigned long long ull; ++ aufs_bindex_t bindex, btop, bbot, bfound; ++ struct file *file; ++ struct au_fidir *fidir; ++ struct au_hfile *hfile; ++ ++ for (ull = 0; ull < opened; ull++) { ++ file = to_free[ull]; ++ if (unlikely(!file)) ++ break; ++ ++ /* AuDbg("%pD\n", file); */ ++ AuDebugOn(!d_is_dir(file->f_path.dentry)); ++ bfound = -1; ++ fidir = au_fi(file)->fi_hdir; ++ AuDebugOn(!fidir); ++ fi_write_lock(file); ++ btop = au_fbtop(file); ++ bbot = au_fbbot_dir(file); ++ for (bindex = btop; bindex <= bbot; bindex++) { ++ hfile = fidir->fd_hfile + bindex; ++ if (!hfile->hf_file) ++ continue; ++ ++ if (hfile->hf_br->br_id == br_id) { ++ bfound = bindex; ++ break; ++ } ++ } ++ AuDebugOn(bfound < 0); ++ au_set_h_fptr(file, bfound, NULL); ++ if (bfound == btop) { ++ for (btop++; btop <= bbot; btop++) ++ if (au_hf_dir(file, btop)) { ++ au_set_fbtop(file, btop); ++ break; ++ } ++ } ++ fi_write_unlock(file); ++ } ++} ++ ++static void au_br_do_del_brp(struct au_sbinfo *sbinfo, ++ const aufs_bindex_t bindex, ++ const aufs_bindex_t bbot) ++{ ++ struct au_branch **brp, **p; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ brp = sbinfo->si_branch + bindex; ++ if (bindex < bbot) ++ memmove(brp, brp + 1, sizeof(*brp) * (bbot - bindex)); ++ sbinfo->si_branch[0 + bbot] = NULL; ++ sbinfo->si_bbot--; ++ ++ p = au_krealloc(sbinfo->si_branch, sizeof(*p) * bbot, AuGFP_SBILIST, ++ /*may_shrink*/1); ++ if (p) ++ sbinfo->si_branch = p; ++ /* harmless error */ ++} ++ ++static void au_br_do_del_hdp(struct au_dinfo *dinfo, const aufs_bindex_t bindex, ++ const aufs_bindex_t bbot) ++{ ++ struct au_hdentry *hdp, *p; ++ ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ hdp = au_hdentry(dinfo, bindex); ++ if (bindex < bbot) ++ memmove(hdp, hdp + 1, sizeof(*hdp) * (bbot - bindex)); ++ /* au_h_dentry_init(au_hdentry(dinfo, bbot); */ ++ dinfo->di_bbot--; ++ ++ p = au_krealloc(dinfo->di_hdentry, sizeof(*p) * bbot, AuGFP_SBILIST, ++ /*may_shrink*/1); ++ if (p) ++ dinfo->di_hdentry = p; ++ /* harmless error */ ++} ++ ++static void au_br_do_del_hip(struct au_iinfo *iinfo, const aufs_bindex_t bindex, ++ const aufs_bindex_t bbot) ++{ ++ struct au_hinode *hip, *p; ++ ++ AuRwMustWriteLock(&iinfo->ii_rwsem); ++ ++ hip = au_hinode(iinfo, bindex); ++ if (bindex < bbot) ++ memmove(hip, hip + 1, sizeof(*hip) * (bbot - bindex)); ++ /* au_hinode_init(au_hinode(iinfo, bbot)); */ ++ iinfo->ii_bbot--; ++ ++ p = au_krealloc(iinfo->ii_hinode, sizeof(*p) * bbot, AuGFP_SBILIST, ++ /*may_shrink*/1); ++ if (p) ++ iinfo->ii_hinode = p; ++ /* harmless error */ ++} ++ ++static void au_br_do_del(struct super_block *sb, aufs_bindex_t bindex, ++ struct au_branch *br) ++{ ++ aufs_bindex_t bbot; ++ struct au_sbinfo *sbinfo; ++ struct dentry *root, *h_root; ++ struct inode *inode, *h_inode; ++ struct au_hinode *hinode; ++ ++ SiMustWriteLock(sb); ++ ++ root = sb->s_root; ++ inode = d_inode(root); ++ sbinfo = au_sbi(sb); ++ bbot = sbinfo->si_bbot; ++ ++ h_root = au_h_dptr(root, bindex); ++ hinode = au_hi(inode, bindex); ++ h_inode = au_igrab(hinode->hi_inode); ++ au_hiput(hinode); ++ ++ au_sbilist_lock(); ++ au_br_do_del_brp(sbinfo, bindex, bbot); ++ au_br_do_del_hdp(au_di(root), bindex, bbot); ++ au_br_do_del_hip(au_ii(inode), bindex, bbot); ++ au_sbilist_unlock(); ++ ++ /* ignore an error */ ++ au_dr_br_fin(sb, br); /* always, regardless the mount option */ ++ ++ dput(h_root); ++ iput(h_inode); ++ au_br_do_free(br); ++} ++ ++static unsigned long long empty_cb(struct super_block *sb, void *array, ++ unsigned long long max, void *arg) ++{ ++ return max; ++} ++ ++int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount) ++{ ++ int err, rerr, i; ++ unsigned long long opened; ++ unsigned int mnt_flags; ++ aufs_bindex_t bindex, bbot, br_id; ++ unsigned char do_wh, verbose; ++ struct au_branch *br; ++ struct au_wbr *wbr; ++ struct dentry *root; ++ struct file **to_free; ++ ++ err = 0; ++ opened = 0; ++ to_free = NULL; ++ root = sb->s_root; ++ bindex = au_find_dbindex(root, del->h_path.dentry); ++ if (bindex < 0) { ++ if (remount) ++ goto out; /* success */ ++ err = -ENOENT; ++ pr_err("%s no such branch\n", del->pathname); ++ goto out; ++ } ++ AuDbg("bindex b%d\n", bindex); ++ ++ err = -EBUSY; ++ mnt_flags = au_mntflags(sb); ++ verbose = !!au_opt_test(mnt_flags, VERBOSE); ++ bbot = au_sbbot(sb); ++ if (unlikely(!bbot)) { ++ AuVerbose(verbose, "no more branches left\n"); ++ goto out; ++ } ++ ++ br = au_sbr(sb, bindex); ++ AuDebugOn(!path_equal(&br->br_path, &del->h_path)); ++ if (unlikely(au_lcnt_read(&br->br_count, /*do_rev*/1))) { ++ AuVerbose(verbose, "br %pd2 is busy now\n", del->h_path.dentry); ++ goto out; ++ } ++ ++ br_id = br->br_id; ++ opened = au_lcnt_read(&br->br_nfiles, /*do_rev*/1); ++ if (unlikely(opened)) { ++ to_free = au_array_alloc(&opened, empty_cb, sb, NULL); ++ err = PTR_ERR(to_free); ++ if (IS_ERR(to_free)) ++ goto out; ++ ++ err = test_file_busy(sb, br_id, to_free, opened); ++ if (unlikely(err)) { ++ AuVerbose(verbose, "%llu file(s) opened\n", opened); ++ goto out; ++ } ++ } ++ ++ wbr = br->br_wbr; ++ do_wh = wbr && (wbr->wbr_whbase || wbr->wbr_plink || wbr->wbr_orph); ++ if (do_wh) { ++ /* instead of WbrWhMustWriteLock(wbr) */ ++ SiMustWriteLock(sb); ++ for (i = 0; i < AuBrWh_Last; i++) { ++ dput(wbr->wbr_wh[i]); ++ wbr->wbr_wh[i] = NULL; ++ } ++ } ++ ++ err = test_children_busy(root, bindex, verbose); ++ if (unlikely(err)) { ++ if (do_wh) ++ goto out_wh; ++ goto out; ++ } ++ ++ err = 0; ++ if (to_free) { ++ /* ++ * now we confirmed the branch is deletable. ++ * let's free the remaining opened dirs on the branch. ++ */ ++ di_write_unlock(root); ++ br_del_file(to_free, opened, br_id); ++ di_write_lock_child(root); ++ } ++ ++ sysaufs_brs_del(sb, bindex); /* remove successors */ ++ dbgaufs_xino_del(br); /* remove one */ ++ au_br_do_del(sb, bindex, br); ++ sysaufs_brs_add(sb, bindex); /* append successors */ ++ dbgaufs_brs_add(sb, bindex, /*topdown*/1); /* rename successors */ ++ ++ if (!bindex) { ++ au_cpup_attr_all(d_inode(root), /*force*/1); ++ sb->s_maxbytes = au_sbr_sb(sb, 0)->s_maxbytes; ++ } else ++ au_sub_nlink(d_inode(root), d_inode(del->h_path.dentry)); ++ if (au_opt_test(mnt_flags, PLINK)) ++ au_plink_half_refresh(sb, br_id); ++ ++ goto out; /* success */ ++ ++out_wh: ++ /* revert */ ++ rerr = au_br_init_wh(sb, br, br->br_perm); ++ if (rerr) ++ pr_warn("failed re-creating base whiteout, %s. (%d)\n", ++ del->pathname, rerr); ++out: ++ if (to_free) ++ au_farray_free(to_free, opened); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_ibusy(struct super_block *sb, struct aufs_ibusy __user *arg) ++{ ++ int err; ++ aufs_bindex_t btop, bbot; ++ struct aufs_ibusy ibusy; ++ struct inode *inode, *h_inode; ++ ++ err = -EPERM; ++ if (unlikely(!capable(CAP_SYS_ADMIN))) ++ goto out; ++ ++ err = copy_from_user(&ibusy, arg, sizeof(ibusy)); ++ if (!err) ++ /* VERIFY_WRITE */ ++ err = !access_ok(&arg->h_ino, sizeof(arg->h_ino)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out; ++ } ++ ++ err = -EINVAL; ++ si_read_lock(sb, AuLock_FLUSH); ++ if (unlikely(ibusy.bindex < 0 || ibusy.bindex > au_sbbot(sb))) ++ goto out_unlock; ++ ++ err = 0; ++ ibusy.h_ino = 0; /* invalid */ ++ inode = ilookup(sb, ibusy.ino); ++ if (!inode ++ || inode->i_ino == AUFS_ROOT_INO ++ || au_is_bad_inode(inode)) ++ goto out_unlock; ++ ++ ii_read_lock_child(inode); ++ btop = au_ibtop(inode); ++ bbot = au_ibbot(inode); ++ if (btop <= ibusy.bindex && ibusy.bindex <= bbot) { ++ h_inode = au_h_iptr(inode, ibusy.bindex); ++ if (h_inode && au_test_ibusy(inode, btop, bbot)) ++ ibusy.h_ino = h_inode->i_ino; ++ } ++ ii_read_unlock(inode); ++ iput(inode); ++ ++out_unlock: ++ si_read_unlock(sb); ++ if (!err) { ++ err = __put_user(ibusy.h_ino, &arg->h_ino); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ } ++ } ++out: ++ return err; ++} ++ ++long au_ibusy_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_ibusy(file->f_path.dentry->d_sb, (void __user *)arg); ++} ++ ++#ifdef CONFIG_COMPAT ++long au_ibusy_compat_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_ibusy(file->f_path.dentry->d_sb, compat_ptr(arg)); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * change a branch permission ++ */ ++ ++static void au_warn_ima(void) ++{ ++#ifdef CONFIG_IMA ++ /* since it doesn't support mark_files_ro() */ ++ AuWarn1("RW -> RO makes IMA to produce wrong message\n"); ++#endif ++} ++ ++static int do_need_sigen_inc(int a, int b) ++{ ++ return au_br_whable(a) && !au_br_whable(b); ++} ++ ++static int need_sigen_inc(int old, int new) ++{ ++ return do_need_sigen_inc(old, new) ++ || do_need_sigen_inc(new, old); ++} ++ ++static int au_br_mod_files_ro(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ int err, do_warn; ++ unsigned int mnt_flags; ++ unsigned long long ull, max; ++ aufs_bindex_t br_id; ++ unsigned char verbose, writer; ++ struct file *file, *hf, **array; ++ struct au_hfile *hfile; ++ struct inode *h_inode; ++ ++ mnt_flags = au_mntflags(sb); ++ verbose = !!au_opt_test(mnt_flags, VERBOSE); ++ ++ array = au_farray_alloc(sb, &max); ++ err = PTR_ERR(array); ++ if (IS_ERR(array)) ++ goto out; ++ ++ do_warn = 0; ++ br_id = au_sbr_id(sb, bindex); ++ for (ull = 0; ull < max; ull++) { ++ file = array[ull]; ++ if (unlikely(!file)) ++ break; ++ ++ /* AuDbg("%pD\n", file); */ ++ fi_read_lock(file); ++ if (unlikely(au_test_mmapped(file))) { ++ err = -EBUSY; ++ AuVerbose(verbose, "mmapped %pD\n", file); ++ AuDbgFile(file); ++ FiMustNoWaiters(file); ++ fi_read_unlock(file); ++ goto out_array; ++ } ++ ++ hfile = &au_fi(file)->fi_htop; ++ hf = hfile->hf_file; ++ if (!d_is_reg(file->f_path.dentry) ++ || !(file->f_mode & FMODE_WRITE) ++ || hfile->hf_br->br_id != br_id ++ || !(hf->f_mode & FMODE_WRITE)) ++ array[ull] = NULL; ++ else { ++ do_warn = 1; ++ get_file(file); ++ } ++ ++ FiMustNoWaiters(file); ++ fi_read_unlock(file); ++ fput(file); ++ } ++ ++ err = 0; ++ if (do_warn) ++ au_warn_ima(); ++ ++ for (ull = 0; ull < max; ull++) { ++ file = array[ull]; ++ if (!file) ++ continue; ++ ++ /* todo: already flushed? */ ++ /* ++ * fs/super.c:mark_files_ro() is gone, but aufs keeps its ++ * approach which resets f_mode and calls mnt_drop_write() and ++ * file_release_write() for each file, because the branch ++ * attribute in aufs world is totally different from the native ++ * fs rw/ro mode. ++ */ ++ /* fi_read_lock(file); */ ++ hfile = &au_fi(file)->fi_htop; ++ hf = hfile->hf_file; ++ /* fi_read_unlock(file); */ ++ spin_lock(&hf->f_lock); ++ writer = !!(hf->f_mode & FMODE_WRITER); ++ hf->f_mode &= ~(FMODE_WRITE | FMODE_WRITER); ++ spin_unlock(&hf->f_lock); ++ if (writer) { ++ h_inode = file_inode(hf); ++ if (hf->f_mode & FMODE_READ) ++ i_readcount_inc(h_inode); ++ put_write_access(h_inode); ++ __mnt_drop_write(hf->f_path.mnt); ++ } ++ } ++ ++out_array: ++ au_farray_free(array, max); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount, ++ int *do_refresh) ++{ ++ int err, rerr; ++ aufs_bindex_t bindex; ++ struct dentry *root; ++ struct au_branch *br; ++ struct au_br_fhsm *bf; ++ ++ root = sb->s_root; ++ bindex = au_find_dbindex(root, mod->h_root); ++ if (bindex < 0) { ++ if (remount) ++ return 0; /* success */ ++ err = -ENOENT; ++ pr_err("%s no such branch\n", mod->path); ++ goto out; ++ } ++ AuDbg("bindex b%d\n", bindex); ++ ++ err = test_br(d_inode(mod->h_root), mod->perm, mod->path); ++ if (unlikely(err)) ++ goto out; ++ ++ br = au_sbr(sb, bindex); ++ AuDebugOn(mod->h_root != au_br_dentry(br)); ++ if (br->br_perm == mod->perm) ++ return 0; /* success */ ++ ++ /* pre-allocate for non-fhsm --> fhsm */ ++ bf = NULL; ++ if (!au_br_fhsm(br->br_perm) && au_br_fhsm(mod->perm)) { ++ err = au_fhsm_br_alloc(br); ++ if (unlikely(err)) ++ goto out; ++ bf = br->br_fhsm; ++ br->br_fhsm = NULL; ++ } ++ ++ if (au_br_writable(br->br_perm)) { ++ /* remove whiteout base */ ++ err = au_br_init_wh(sb, br, mod->perm); ++ if (unlikely(err)) ++ goto out_bf; ++ ++ if (!au_br_writable(mod->perm)) { ++ /* rw --> ro, file might be mmapped */ ++ DiMustNoWaiters(root); ++ IiMustNoWaiters(d_inode(root)); ++ di_write_unlock(root); ++ err = au_br_mod_files_ro(sb, bindex); ++ /* aufs_write_lock() calls ..._child() */ ++ di_write_lock_child(root); ++ ++ if (unlikely(err)) { ++ rerr = -ENOMEM; ++ br->br_wbr = kzalloc(sizeof(*br->br_wbr), ++ GFP_NOFS); ++ if (br->br_wbr) ++ rerr = au_wbr_init(br, sb, br->br_perm); ++ if (unlikely(rerr)) { ++ AuIOErr("nested error %d (%d)\n", ++ rerr, err); ++ br->br_perm = mod->perm; ++ } ++ } ++ } ++ } else if (au_br_writable(mod->perm)) { ++ /* ro --> rw */ ++ err = -ENOMEM; ++ br->br_wbr = kzalloc(sizeof(*br->br_wbr), GFP_NOFS); ++ if (br->br_wbr) { ++ err = au_wbr_init(br, sb, mod->perm); ++ if (unlikely(err)) { ++ au_kfree_rcu(br->br_wbr); ++ br->br_wbr = NULL; ++ } ++ } ++ } ++ if (unlikely(err)) ++ goto out_bf; ++ ++ if (au_br_fhsm(br->br_perm)) { ++ if (!au_br_fhsm(mod->perm)) { ++ /* fhsm --> non-fhsm */ ++ au_br_fhsm_fin(br->br_fhsm); ++ au_kfree_rcu(br->br_fhsm); ++ br->br_fhsm = NULL; ++ } ++ } else if (au_br_fhsm(mod->perm)) ++ /* non-fhsm --> fhsm */ ++ br->br_fhsm = bf; ++ ++ *do_refresh |= need_sigen_inc(br->br_perm, mod->perm); ++ br->br_perm = mod->perm; ++ goto out; /* success */ ++ ++out_bf: ++ au_kfree_try_rcu(bf); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_br_stfs(struct au_branch *br, struct aufs_stfs *stfs) ++{ ++ int err; ++ struct kstatfs kstfs; ++ ++ err = vfs_statfs(&br->br_path, &kstfs); ++ if (!err) { ++ stfs->f_blocks = kstfs.f_blocks; ++ stfs->f_bavail = kstfs.f_bavail; ++ stfs->f_files = kstfs.f_files; ++ stfs->f_ffree = kstfs.f_ffree; ++ } ++ ++ return err; ++} +diff -Nurp linux-5.15.37/fs/aufs/branch.h linux-5.15.37-aufs/fs/aufs/branch.h +--- linux-5.15.37/fs/aufs/branch.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/branch.h 2022-04-08 20:22:30.611616426 +0300 +@@ -0,0 +1,362 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * branch filesystems and xino for them ++ */ ++ ++#ifndef __AUFS_BRANCH_H__ ++#define __AUFS_BRANCH_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "dirren.h" ++#include "dynop.h" ++#include "lcnt.h" ++#include "rwsem.h" ++#include "super.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* a xino file */ ++struct au_xino { ++ struct file **xi_file; ++ unsigned int xi_nfile; ++ ++ struct { ++ spinlock_t spin; ++ ino_t *array; ++ int total; ++ /* reserved for future use */ ++ /* unsigned long *bitmap; */ ++ wait_queue_head_t wqh; ++ } xi_nondir; ++ ++ struct mutex xi_mtx; /* protects xi_file array */ ++ struct hlist_bl_head xi_writing; ++ ++ atomic_t xi_truncating; ++ ++ struct kref xi_kref; ++}; ++ ++/* File-based Hierarchical Storage Management */ ++struct au_br_fhsm { ++#ifdef CONFIG_AUFS_FHSM ++ struct mutex bf_lock; ++ unsigned long bf_jiffy; ++ struct aufs_stfs bf_stfs; ++ int bf_readable; ++#endif ++}; ++ ++/* members for writable branch only */ ++enum {AuBrWh_BASE, AuBrWh_PLINK, AuBrWh_ORPH, AuBrWh_Last}; ++struct au_wbr { ++ struct au_rwsem wbr_wh_rwsem; ++ struct dentry *wbr_wh[AuBrWh_Last]; ++ atomic_t wbr_wh_running; ++#define wbr_whbase wbr_wh[AuBrWh_BASE] /* whiteout base */ ++#define wbr_plink wbr_wh[AuBrWh_PLINK] /* pseudo-link dir */ ++#define wbr_orph wbr_wh[AuBrWh_ORPH] /* dir for orphans */ ++ ++ /* mfs mode */ ++ unsigned long long wbr_bytes; ++}; ++ ++/* ext2 has 3 types of operations at least, ext3 has 4 */ ++#define AuBrDynOp (AuDyLast * 4) ++ ++#ifdef CONFIG_AUFS_HFSNOTIFY ++/* support for asynchronous destruction */ ++struct au_br_hfsnotify { ++ struct fsnotify_group *hfsn_group; ++}; ++#endif ++ ++/* sysfs entries */ ++struct au_brsysfs { ++ char name[16]; ++ struct attribute attr; ++}; ++ ++enum { ++ AuBrSysfs_BR, ++ AuBrSysfs_BRID, ++ AuBrSysfs_Last ++}; ++ ++/* protected by superblock rwsem */ ++struct au_branch { ++ struct au_xino *br_xino; ++ ++ aufs_bindex_t br_id; ++ ++ int br_perm; ++ struct path br_path; ++ spinlock_t br_dykey_lock; ++ struct au_dykey *br_dykey[AuBrDynOp]; ++ au_lcnt_t br_nfiles; /* opened files */ ++ au_lcnt_t br_count; /* in-use for other */ ++ ++ struct au_wbr *br_wbr; ++ struct au_br_fhsm *br_fhsm; ++ ++#ifdef CONFIG_AUFS_HFSNOTIFY ++ struct au_br_hfsnotify *br_hfsn; ++#endif ++ ++#ifdef CONFIG_SYSFS ++ /* entries under sysfs per mount-point */ ++ struct au_brsysfs br_sysfs[AuBrSysfs_Last]; ++#endif ++ ++#ifdef CONFIG_DEBUG_FS ++ struct dentry *br_dbgaufs; /* xino */ ++#endif ++ ++ struct au_dr_br br_dirren; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct vfsmount *au_br_mnt(struct au_branch *br) ++{ ++ return br->br_path.mnt; ++} ++ ++static inline struct dentry *au_br_dentry(struct au_branch *br) ++{ ++ return br->br_path.dentry; ++} ++ ++static inline struct user_namespace *au_br_userns(struct au_branch *br) ++{ ++ return mnt_user_ns(br->br_path.mnt); ++} ++ ++static inline struct super_block *au_br_sb(struct au_branch *br) ++{ ++ return au_br_mnt(br)->mnt_sb; ++} ++ ++static inline int au_br_rdonly(struct au_branch *br) ++{ ++ return (sb_rdonly(au_br_sb(br)) ++ || !au_br_writable(br->br_perm)) ++ ? -EROFS : 0; ++} ++ ++static inline int au_br_hnotifyable(int brperm __maybe_unused) ++{ ++#ifdef CONFIG_AUFS_HNOTIFY ++ return !(brperm & AuBrPerm_RR); ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_br_test_oflag(int oflag, struct au_branch *br) ++{ ++ int err, exec_flag; ++ ++ err = 0; ++ exec_flag = oflag & __FMODE_EXEC; ++ if (unlikely(exec_flag && path_noexec(&br->br_path))) ++ err = -EACCES; ++ ++ return err; ++} ++ ++static inline void au_xino_get(struct au_branch *br) ++{ ++ struct au_xino *xi; ++ ++ xi = br->br_xino; ++ if (xi) ++ kref_get(&xi->xi_kref); ++} ++ ++static inline int au_xino_count(struct au_branch *br) ++{ ++ int v; ++ struct au_xino *xi; ++ ++ v = 0; ++ xi = br->br_xino; ++ if (xi) ++ v = kref_read(&xi->xi_kref); ++ ++ return v; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* branch.c */ ++struct au_sbinfo; ++void au_br_free(struct au_sbinfo *sinfo); ++int au_br_index(struct super_block *sb, aufs_bindex_t br_id); ++struct au_opt_add; ++int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount); ++struct au_opt_del; ++int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount); ++long au_ibusy_ioctl(struct file *file, unsigned long arg); ++#ifdef CONFIG_COMPAT ++long au_ibusy_compat_ioctl(struct file *file, unsigned long arg); ++#endif ++struct au_opt_mod; ++int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount, ++ int *do_refresh); ++struct aufs_stfs; ++int au_br_stfs(struct au_branch *br, struct aufs_stfs *stfs); ++ ++/* xino.c */ ++static const loff_t au_loff_max = LLONG_MAX; ++ ++aufs_bindex_t au_xi_root(struct super_block *sb, struct dentry *dentry); ++struct file *au_xino_create(struct super_block *sb, char *fpath, int silent, ++ int wbrtop); ++struct file *au_xino_create2(struct super_block *sb, struct path *base, ++ struct file *copy_src); ++struct au_xi_new { ++ struct au_xino *xi; /* switch between xino and xigen */ ++ int idx; ++ struct path *base; ++ struct file *copy_src; ++}; ++struct file *au_xi_new(struct super_block *sb, struct au_xi_new *xinew); ++ ++int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t *ino); ++int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t ino); ++ssize_t xino_fread(struct file *file, void *buf, size_t size, loff_t *pos); ++ssize_t xino_fwrite(struct file *file, void *buf, size_t size, loff_t *pos); ++ ++int au_xib_trunc(struct super_block *sb); ++int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex, int idx_begin); ++ ++struct au_xino *au_xino_alloc(unsigned int nfile); ++int au_xino_put(struct au_branch *br); ++struct file *au_xino_file1(struct au_xino *xi); ++ ++struct au_opt_xino; ++void au_xino_clr(struct super_block *sb); ++int au_xino_set(struct super_block *sb, struct au_opt_xino *xiopt, int remount); ++struct file *au_xino_def(struct super_block *sb); ++int au_xino_init_br(struct super_block *sb, struct au_branch *br, ino_t hino, ++ struct path *base); ++ ++ino_t au_xino_new_ino(struct super_block *sb); ++void au_xino_delete_inode(struct inode *inode, const int unlinked); ++ ++void au_xinondir_leave(struct super_block *sb, aufs_bindex_t bindex, ++ ino_t h_ino, int idx); ++int au_xinondir_enter(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ int *idx); ++ ++int au_xino_path(struct seq_file *seq, struct file *file); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* @idx is signed to accept -1 meaning the first file */ ++static inline struct file *au_xino_file(struct au_xino *xi, int idx) ++{ ++ struct file *file; ++ ++ file = NULL; ++ if (!xi) ++ goto out; ++ ++ if (idx >= 0) { ++ if (idx < xi->xi_nfile) ++ file = xi->xi_file[idx]; ++ } else ++ file = au_xino_file1(xi); ++ ++out: ++ return file; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* Superblock to branch */ ++static inline ++aufs_bindex_t au_sbr_id(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_sbr(sb, bindex)->br_id; ++} ++ ++static inline ++struct vfsmount *au_sbr_mnt(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_br_mnt(au_sbr(sb, bindex)); ++} ++ ++static inline ++struct user_namespace *au_sbr_userns(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_br_userns(au_sbr(sb, bindex)); ++} ++ ++static inline ++struct super_block *au_sbr_sb(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_br_sb(au_sbr(sb, bindex)); ++} ++ ++static inline int au_sbr_perm(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_sbr(sb, bindex)->br_perm; ++} ++ ++static inline int au_sbr_whable(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_br_whable(au_sbr_perm(sb, bindex)); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define wbr_wh_read_lock(wbr) au_rw_read_lock(&(wbr)->wbr_wh_rwsem) ++#define wbr_wh_write_lock(wbr) au_rw_write_lock(&(wbr)->wbr_wh_rwsem) ++#define wbr_wh_read_trylock(wbr) au_rw_read_trylock(&(wbr)->wbr_wh_rwsem) ++#define wbr_wh_write_trylock(wbr) au_rw_write_trylock(&(wbr)->wbr_wh_rwsem) ++/* ++#define wbr_wh_read_trylock_nested(wbr) \ ++ au_rw_read_trylock_nested(&(wbr)->wbr_wh_rwsem) ++#define wbr_wh_write_trylock_nested(wbr) \ ++ au_rw_write_trylock_nested(&(wbr)->wbr_wh_rwsem) ++*/ ++ ++#define wbr_wh_read_unlock(wbr) au_rw_read_unlock(&(wbr)->wbr_wh_rwsem) ++#define wbr_wh_write_unlock(wbr) au_rw_write_unlock(&(wbr)->wbr_wh_rwsem) ++#define wbr_wh_downgrade_lock(wbr) au_rw_dgrade_lock(&(wbr)->wbr_wh_rwsem) ++ ++#define WbrWhMustNoWaiters(wbr) AuRwMustNoWaiters(&(wbr)->wbr_wh_rwsem) ++#define WbrWhMustAnyLock(wbr) AuRwMustAnyLock(&(wbr)->wbr_wh_rwsem) ++#define WbrWhMustWriteLock(wbr) AuRwMustWriteLock(&(wbr)->wbr_wh_rwsem) ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_FHSM ++static inline void au_br_fhsm_init(struct au_br_fhsm *brfhsm) ++{ ++ mutex_init(&brfhsm->bf_lock); ++ brfhsm->bf_jiffy = 0; ++ brfhsm->bf_readable = 0; ++} ++ ++static inline void au_br_fhsm_fin(struct au_br_fhsm *brfhsm) ++{ ++ mutex_destroy(&brfhsm->bf_lock); ++} ++#else ++AuStubVoid(au_br_fhsm_init, struct au_br_fhsm *brfhsm) ++AuStubVoid(au_br_fhsm_fin, struct au_br_fhsm *brfhsm) ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_BRANCH_H__ */ +diff -Nurp linux-5.15.37/fs/aufs/cpup.c linux-5.15.37-aufs/fs/aufs/cpup.c +--- linux-5.15.37/fs/aufs/cpup.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/cpup.c 2022-04-08 20:22:30.611616426 +0300 +@@ -0,0 +1,1446 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * copy-up functions, see wbr_policy.c for copy-down ++ */ ++ ++#include ++#include ++#include ++#include "aufs.h" ++ ++void au_cpup_attr_flags(struct inode *dst, unsigned int iflags) ++{ ++ const unsigned int mask = S_DEAD | S_SWAPFILE | S_PRIVATE ++ | S_NOATIME | S_NOCMTIME | S_AUTOMOUNT; ++ ++ BUILD_BUG_ON(sizeof(iflags) != sizeof(dst->i_flags)); ++ ++ dst->i_flags |= iflags & ~mask; ++ if (au_test_fs_notime(dst->i_sb)) ++ dst->i_flags |= S_NOATIME | S_NOCMTIME; ++} ++ ++void au_cpup_attr_timesizes(struct inode *inode) ++{ ++ struct inode *h_inode; ++ ++ h_inode = au_h_iptr(inode, au_ibtop(inode)); ++ fsstack_copy_attr_times(inode, h_inode); ++ fsstack_copy_inode_size(inode, h_inode); ++} ++ ++void au_cpup_attr_nlink(struct inode *inode, int force) ++{ ++ struct inode *h_inode; ++ struct super_block *sb; ++ aufs_bindex_t bindex, bbot; ++ ++ sb = inode->i_sb; ++ bindex = au_ibtop(inode); ++ h_inode = au_h_iptr(inode, bindex); ++ if (!force ++ && !S_ISDIR(h_inode->i_mode) ++ && au_opt_test(au_mntflags(sb), PLINK) ++ && au_plink_test(inode)) ++ return; ++ ++ /* ++ * 0 can happen in revalidating. ++ * h_inode->i_mutex may not be held here, but it is harmless since once ++ * i_nlink reaches 0, it will never become positive except O_TMPFILE ++ * case. ++ * todo: O_TMPFILE+linkat(AT_SYMLINK_FOLLOW) bypassing aufs may cause ++ * the incorrect link count. ++ */ ++ set_nlink(inode, h_inode->i_nlink); ++ ++ /* ++ * fewer nlink makes find(1) noisy, but larger nlink doesn't. ++ * it may includes whplink directory. ++ */ ++ if (S_ISDIR(h_inode->i_mode)) { ++ bbot = au_ibbot(inode); ++ for (bindex++; bindex <= bbot; bindex++) { ++ h_inode = au_h_iptr(inode, bindex); ++ if (h_inode) ++ au_add_nlink(inode, h_inode); ++ } ++ } ++} ++ ++void au_cpup_attr_changeable(struct inode *inode) ++{ ++ struct inode *h_inode; ++ ++ h_inode = au_h_iptr(inode, au_ibtop(inode)); ++ inode->i_mode = h_inode->i_mode; ++ inode->i_uid = h_inode->i_uid; ++ inode->i_gid = h_inode->i_gid; ++ au_cpup_attr_timesizes(inode); ++ au_cpup_attr_flags(inode, h_inode->i_flags); ++} ++ ++void au_cpup_igen(struct inode *inode, struct inode *h_inode) ++{ ++ struct au_iinfo *iinfo = au_ii(inode); ++ ++ IiMustWriteLock(inode); ++ ++ iinfo->ii_higen = h_inode->i_generation; ++ iinfo->ii_hsb1 = h_inode->i_sb; ++} ++ ++void au_cpup_attr_all(struct inode *inode, int force) ++{ ++ struct inode *h_inode; ++ ++ h_inode = au_h_iptr(inode, au_ibtop(inode)); ++ au_cpup_attr_changeable(inode); ++ if (inode->i_nlink > 0) ++ au_cpup_attr_nlink(inode, force); ++ inode->i_rdev = h_inode->i_rdev; ++ inode->i_blkbits = h_inode->i_blkbits; ++ au_cpup_igen(inode, h_inode); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* Note: dt_dentry and dt_h_dentry are not dget/dput-ed */ ++ ++/* keep the timestamps of the parent dir when cpup */ ++void au_dtime_store(struct au_dtime *dt, struct dentry *dentry, ++ struct path *h_path) ++{ ++ struct inode *h_inode; ++ ++ dt->dt_dentry = dentry; ++ dt->dt_h_path = *h_path; ++ h_inode = d_inode(h_path->dentry); ++ dt->dt_atime = h_inode->i_atime; ++ dt->dt_mtime = h_inode->i_mtime; ++ /* smp_mb(); */ ++} ++ ++void au_dtime_revert(struct au_dtime *dt) ++{ ++ struct iattr attr; ++ int err; ++ ++ attr.ia_atime = dt->dt_atime; ++ attr.ia_mtime = dt->dt_mtime; ++ attr.ia_valid = ATTR_FORCE | ATTR_MTIME | ATTR_MTIME_SET ++ | ATTR_ATIME | ATTR_ATIME_SET; ++ ++ /* no delegation since this is a directory */ ++ err = vfsub_notify_change(&dt->dt_h_path, &attr, /*delegated*/NULL); ++ if (unlikely(err)) ++ pr_warn("restoring timestamps failed(%d). ignored\n", err); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* internal use only */ ++struct au_cpup_reg_attr { ++ int valid; ++ struct kstat st; ++ unsigned int iflags; /* inode->i_flags */ ++}; ++ ++static noinline_for_stack ++int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct path *h_src, ++ struct au_cpup_reg_attr *h_src_attr) ++{ ++ int err, sbits, icex; ++ unsigned int mnt_flags; ++ unsigned char verbose; ++ struct iattr ia; ++ struct path h_path; ++ struct inode *h_isrc, *h_idst; ++ struct kstat *h_st; ++ struct au_branch *br; ++ ++ br = au_sbr(dst->d_sb, bindex); ++ h_path.mnt = au_br_mnt(br); ++ h_path.dentry = au_h_dptr(dst, bindex); ++ h_idst = d_inode(h_path.dentry); ++ h_isrc = d_inode(h_src->dentry); ++ ia.ia_valid = ATTR_FORCE | ATTR_UID | ATTR_GID ++ | ATTR_ATIME | ATTR_MTIME ++ | ATTR_ATIME_SET | ATTR_MTIME_SET; ++ if (h_src_attr && h_src_attr->valid) { ++ h_st = &h_src_attr->st; ++ ia.ia_uid = h_st->uid; ++ ia.ia_gid = h_st->gid; ++ ia.ia_atime = h_st->atime; ++ ia.ia_mtime = h_st->mtime; ++ if (h_idst->i_mode != h_st->mode ++ && !S_ISLNK(h_idst->i_mode)) { ++ ia.ia_valid |= ATTR_MODE; ++ ia.ia_mode = h_st->mode; ++ } ++ sbits = !!(h_st->mode & (S_ISUID | S_ISGID)); ++ au_cpup_attr_flags(h_idst, h_src_attr->iflags); ++ } else { ++ ia.ia_uid = h_isrc->i_uid; ++ ia.ia_gid = h_isrc->i_gid; ++ ia.ia_atime = h_isrc->i_atime; ++ ia.ia_mtime = h_isrc->i_mtime; ++ if (h_idst->i_mode != h_isrc->i_mode ++ && !S_ISLNK(h_idst->i_mode)) { ++ ia.ia_valid |= ATTR_MODE; ++ ia.ia_mode = h_isrc->i_mode; ++ } ++ sbits = !!(h_isrc->i_mode & (S_ISUID | S_ISGID)); ++ au_cpup_attr_flags(h_idst, h_isrc->i_flags); ++ } ++ /* no delegation since it is just created */ ++ err = vfsub_notify_change(&h_path, &ia, /*delegated*/NULL); ++ ++ /* is this nfs only? */ ++ if (!err && sbits && au_test_nfs(h_path.dentry->d_sb)) { ++ ia.ia_valid = ATTR_FORCE | ATTR_MODE; ++ ia.ia_mode = h_isrc->i_mode; ++ err = vfsub_notify_change(&h_path, &ia, /*delegated*/NULL); ++ } ++ ++ icex = br->br_perm & AuBrAttr_ICEX; ++ if (!err) { ++ mnt_flags = au_mntflags(dst->d_sb); ++ verbose = !!au_opt_test(mnt_flags, VERBOSE); ++ err = au_cpup_xattr(&h_path, h_src, icex, verbose); ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_copy_file(struct file *dst, struct file *src, loff_t len, ++ char *buf, unsigned long blksize) ++{ ++ int err; ++ size_t sz, rbytes, wbytes; ++ unsigned char all_zero; ++ char *p, *zp; ++ struct inode *h_inode; ++ /* reduce stack usage */ ++ struct iattr *ia; ++ ++ zp = page_address(ZERO_PAGE(0)); ++ if (unlikely(!zp)) ++ return -ENOMEM; /* possible? */ ++ ++ err = 0; ++ all_zero = 0; ++ while (len) { ++ AuDbg("len %lld\n", len); ++ sz = blksize; ++ if (len < blksize) ++ sz = len; ++ ++ rbytes = 0; ++ /* todo: signal_pending? */ ++ while (!rbytes || err == -EAGAIN || err == -EINTR) { ++ rbytes = vfsub_read_k(src, buf, sz, &src->f_pos); ++ err = rbytes; ++ } ++ if (unlikely(err < 0)) ++ break; ++ ++ all_zero = 0; ++ if (len >= rbytes && rbytes == blksize) ++ all_zero = !memcmp(buf, zp, rbytes); ++ if (!all_zero) { ++ wbytes = rbytes; ++ p = buf; ++ while (wbytes) { ++ size_t b; ++ ++ b = vfsub_write_k(dst, p, wbytes, &dst->f_pos); ++ err = b; ++ /* todo: signal_pending? */ ++ if (unlikely(err == -EAGAIN || err == -EINTR)) ++ continue; ++ if (unlikely(err < 0)) ++ break; ++ wbytes -= b; ++ p += b; ++ } ++ if (unlikely(err < 0)) ++ break; ++ } else { ++ loff_t res; ++ ++ AuLabel(hole); ++ res = vfsub_llseek(dst, rbytes, SEEK_CUR); ++ err = res; ++ if (unlikely(res < 0)) ++ break; ++ } ++ len -= rbytes; ++ err = 0; ++ } ++ ++ /* the last block may be a hole */ ++ if (!err && all_zero) { ++ AuLabel(last hole); ++ ++ err = 1; ++ if (au_test_nfs(dst->f_path.dentry->d_sb)) { ++ /* nfs requires this step to make last hole */ ++ /* is this only nfs? */ ++ do { ++ /* todo: signal_pending? */ ++ err = vfsub_write_k(dst, "\0", 1, &dst->f_pos); ++ } while (err == -EAGAIN || err == -EINTR); ++ if (err == 1) ++ dst->f_pos--; ++ } ++ ++ if (err == 1) { ++ ia = (void *)buf; ++ ia->ia_size = dst->f_pos; ++ ia->ia_valid = ATTR_SIZE | ATTR_FILE; ++ ia->ia_file = dst; ++ h_inode = file_inode(dst); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD2); ++ /* no delegation since it is just created */ ++ err = vfsub_notify_change(&dst->f_path, ia, ++ /*delegated*/NULL); ++ inode_unlock(h_inode); ++ } ++ } ++ ++ return err; ++} ++ ++int au_copy_file(struct file *dst, struct file *src, loff_t len) ++{ ++ int err; ++ unsigned long blksize; ++ unsigned char do_kfree; ++ char *buf; ++ struct super_block *h_sb; ++ ++ err = -ENOMEM; ++ h_sb = file_inode(dst)->i_sb; ++ blksize = h_sb->s_blocksize; ++ if (!blksize || PAGE_SIZE < blksize) ++ blksize = PAGE_SIZE; ++ AuDbg("blksize %lu\n", blksize); ++ do_kfree = (blksize != PAGE_SIZE && blksize >= sizeof(struct iattr *)); ++ if (do_kfree) ++ buf = kmalloc(blksize, GFP_NOFS); ++ else ++ buf = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!buf)) ++ goto out; ++ ++ if (len > (1 << 22)) ++ AuDbg("copying a large file %lld\n", (long long)len); ++ ++ src->f_pos = 0; ++ dst->f_pos = 0; ++ err = au_do_copy_file(dst, src, len, buf, blksize); ++ if (do_kfree) { ++ AuDebugOn(!au_kfree_do_sz_test(blksize)); ++ au_kfree_do_rcu(buf); ++ } else ++ free_page((unsigned long)buf); ++ ++out: ++ return err; ++} ++ ++static int au_do_copy(struct file *dst, struct file *src, loff_t len) ++{ ++ int err; ++ struct super_block *h_src_sb; ++ struct inode *h_src_inode; ++ ++ h_src_inode = file_inode(src); ++ h_src_sb = h_src_inode->i_sb; ++ ++ /* XFS acquires inode_lock */ ++ if (!au_test_xfs(h_src_sb)) ++ err = au_copy_file(dst, src, len); ++ else { ++ inode_unlock_shared(h_src_inode); ++ err = au_copy_file(dst, src, len); ++ inode_lock_shared_nested(h_src_inode, AuLsc_I_CHILD); ++ } ++ ++ return err; ++} ++ ++static int au_clone_or_copy(struct file *dst, struct file *src, loff_t len) ++{ ++ int err; ++ loff_t lo; ++ struct super_block *h_src_sb; ++ struct inode *h_src_inode; ++ ++ h_src_inode = file_inode(src); ++ h_src_sb = h_src_inode->i_sb; ++ if (h_src_sb != file_inode(dst)->i_sb ++ || !dst->f_op->remap_file_range) { ++ err = au_do_copy(dst, src, len); ++ goto out; ++ } ++ ++ if (!au_test_nfs(h_src_sb)) { ++ inode_unlock_shared(h_src_inode); ++ lo = vfsub_clone_file_range(src, dst, len); ++ inode_lock_shared_nested(h_src_inode, AuLsc_I_CHILD); ++ } else ++ lo = vfsub_clone_file_range(src, dst, len); ++ if (lo == len) { ++ err = 0; ++ goto out; /* success */ ++ } else if (lo >= 0) ++ /* todo: possible? */ ++ /* paritially succeeded */ ++ AuDbg("lo %lld, len %lld. Retrying.\n", lo, len); ++ else if (lo != -EOPNOTSUPP) { ++ /* older XFS has a condition in cloning */ ++ err = lo; ++ goto out; ++ } ++ ++ /* the backend fs on NFS may not support cloning */ ++ err = au_do_copy(dst, src, len); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * to support a sparse file which is opened with O_APPEND, ++ * we need to close the file. ++ */ ++static int au_cp_regular(struct au_cp_generic *cpg) ++{ ++ int err, i; ++ enum { SRC, DST }; ++ struct { ++ aufs_bindex_t bindex; ++ unsigned int flags; ++ struct dentry *dentry; ++ int force_wr; ++ struct file *file; ++ } *f, file[] = { ++ { ++ .bindex = cpg->bsrc, ++ .flags = O_RDONLY | O_NOATIME | O_LARGEFILE, ++ }, ++ { ++ .bindex = cpg->bdst, ++ .flags = O_WRONLY | O_NOATIME | O_LARGEFILE, ++ .force_wr = !!au_ftest_cpup(cpg->flags, RWDST), ++ } ++ }; ++ struct au_branch *br; ++ struct super_block *sb, *h_src_sb; ++ struct inode *h_src_inode; ++ struct task_struct *tsk = current; ++ ++ /* bsrc branch can be ro/rw. */ ++ sb = cpg->dentry->d_sb; ++ f = file; ++ for (i = 0; i < 2; i++, f++) { ++ f->dentry = au_h_dptr(cpg->dentry, f->bindex); ++ f->file = au_h_open(cpg->dentry, f->bindex, f->flags, ++ /*file*/NULL, f->force_wr); ++ if (IS_ERR(f->file)) { ++ err = PTR_ERR(f->file); ++ if (i == SRC) ++ goto out; ++ else ++ goto out_src; ++ } ++ } ++ ++ /* try stopping to update while we copyup */ ++ h_src_inode = d_inode(file[SRC].dentry); ++ h_src_sb = h_src_inode->i_sb; ++ if (!au_test_nfs(h_src_sb)) ++ IMustLock(h_src_inode); ++ err = au_clone_or_copy(file[DST].file, file[SRC].file, cpg->len); ++ ++ /* i wonder if we had O_NO_DELAY_FPUT flag */ ++ if (tsk->flags & PF_KTHREAD) ++ __fput_sync(file[DST].file); ++ else { ++ /* it happened actually */ ++ fput(file[DST].file); ++ /* ++ * too bad. ++ * we have to call both since we don't know which place the file ++ * was added to. ++ */ ++ task_work_run(); ++ flush_delayed_fput(); ++ } ++ br = au_sbr(sb, file[DST].bindex); ++ au_lcnt_dec(&br->br_nfiles); ++ ++out_src: ++ fput(file[SRC].file); ++ br = au_sbr(sb, file[SRC].bindex); ++ au_lcnt_dec(&br->br_nfiles); ++out: ++ return err; ++} ++ ++static int au_do_cpup_regular(struct au_cp_generic *cpg, ++ struct au_cpup_reg_attr *h_src_attr) ++{ ++ int err, rerr; ++ loff_t l; ++ struct path h_path; ++ struct inode *h_src_inode, *h_dst_inode; ++ ++ err = 0; ++ h_src_inode = au_h_iptr(d_inode(cpg->dentry), cpg->bsrc); ++ l = i_size_read(h_src_inode); ++ if (cpg->len == -1 || l < cpg->len) ++ cpg->len = l; ++ if (cpg->len) { ++ /* try stopping to update while we are referencing */ ++ inode_lock_shared_nested(h_src_inode, AuLsc_I_CHILD); ++ au_pin_hdir_unlock(cpg->pin); ++ ++ h_path.dentry = au_h_dptr(cpg->dentry, cpg->bsrc); ++ h_path.mnt = au_sbr_mnt(cpg->dentry->d_sb, cpg->bsrc); ++ h_src_attr->iflags = h_src_inode->i_flags; ++ if (!au_test_nfs(h_src_inode->i_sb)) ++ err = vfsub_getattr(&h_path, &h_src_attr->st); ++ else { ++ inode_unlock_shared(h_src_inode); ++ err = vfsub_getattr(&h_path, &h_src_attr->st); ++ inode_lock_shared_nested(h_src_inode, AuLsc_I_CHILD); ++ } ++ if (unlikely(err)) { ++ inode_unlock_shared(h_src_inode); ++ goto out; ++ } ++ h_src_attr->valid = 1; ++ if (!au_test_nfs(h_src_inode->i_sb)) { ++ err = au_cp_regular(cpg); ++ inode_unlock_shared(h_src_inode); ++ } else { ++ inode_unlock_shared(h_src_inode); ++ err = au_cp_regular(cpg); ++ } ++ rerr = au_pin_hdir_relock(cpg->pin); ++ if (!err && rerr) ++ err = rerr; ++ } ++ if (!err && (h_src_inode->i_state & I_LINKABLE)) { ++ h_path.dentry = au_h_dptr(cpg->dentry, cpg->bdst); ++ h_dst_inode = d_inode(h_path.dentry); ++ spin_lock(&h_dst_inode->i_lock); ++ h_dst_inode->i_state |= I_LINKABLE; ++ spin_unlock(&h_dst_inode->i_lock); ++ } ++ ++out: ++ return err; ++} ++ ++static int au_do_cpup_symlink(struct path *h_path, struct dentry *h_src, ++ struct inode *h_dir) ++{ ++ int err; ++ DEFINE_DELAYED_CALL(done); ++ const char *sym; ++ ++ sym = vfs_get_link(h_src, &done); ++ err = PTR_ERR(sym); ++ if (IS_ERR(sym)) ++ goto out; ++ ++ err = vfsub_symlink(h_dir, h_path, sym); ++ ++out: ++ do_delayed_call(&done); ++ return err; ++} ++ ++/* ++ * regardless 'acl' option, reset all ACL. ++ * All ACL will be copied up later from the original entry on the lower branch. ++ */ ++static int au_reset_acl(struct inode *h_dir, struct path *h_path, umode_t mode) ++{ ++ int err; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct user_namespace *h_userns; ++ ++ h_userns = mnt_user_ns(h_path->mnt); ++ h_dentry = h_path->dentry; ++ h_inode = d_inode(h_dentry); ++ /* forget_all_cached_acls(h_inode)); */ ++ err = vfsub_removexattr(h_userns, h_dentry, XATTR_NAME_POSIX_ACL_ACCESS); ++ AuTraceErr(err); ++ if (err == -EOPNOTSUPP) ++ err = 0; ++ if (!err) ++ err = vfsub_acl_chmod(h_userns, h_inode, mode); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_do_cpup_dir(struct au_cp_generic *cpg, struct dentry *dst_parent, ++ struct inode *h_dir, struct path *h_path) ++{ ++ int err; ++ struct inode *dir, *inode; ++ struct user_namespace *h_userns; ++ ++ h_userns = mnt_user_ns(h_path->mnt); ++ err = vfsub_removexattr(h_userns, h_path->dentry, ++ XATTR_NAME_POSIX_ACL_DEFAULT); ++ AuTraceErr(err); ++ if (err == -EOPNOTSUPP) ++ err = 0; ++ if (unlikely(err)) ++ goto out; ++ ++ /* ++ * strange behaviour from the users view, ++ * particularly setattr case ++ */ ++ dir = d_inode(dst_parent); ++ if (au_ibtop(dir) == cpg->bdst) ++ au_cpup_attr_nlink(dir, /*force*/1); ++ inode = d_inode(cpg->dentry); ++ au_cpup_attr_nlink(inode, /*force*/1); ++ ++out: ++ return err; ++} ++ ++static noinline_for_stack ++int cpup_entry(struct au_cp_generic *cpg, struct dentry *dst_parent, ++ struct au_cpup_reg_attr *h_src_attr) ++{ ++ int err; ++ umode_t mode; ++ unsigned int mnt_flags; ++ unsigned char isdir, isreg, force; ++ const unsigned char do_dt = !!au_ftest_cpup(cpg->flags, DTIME); ++ struct au_dtime dt; ++ struct path h_path; ++ struct dentry *h_src, *h_dst, *h_parent; ++ struct inode *h_inode, *h_dir; ++ struct super_block *sb; ++ ++ /* bsrc branch can be ro/rw. */ ++ h_src = au_h_dptr(cpg->dentry, cpg->bsrc); ++ h_inode = d_inode(h_src); ++ AuDebugOn(h_inode != au_h_iptr(d_inode(cpg->dentry), cpg->bsrc)); ++ ++ /* try stopping to be referenced while we are creating */ ++ h_dst = au_h_dptr(cpg->dentry, cpg->bdst); ++ if (au_ftest_cpup(cpg->flags, RENAME)) ++ AuDebugOn(strncmp(h_dst->d_name.name, AUFS_WH_PFX, ++ AUFS_WH_PFX_LEN)); ++ h_parent = h_dst->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ AuDebugOn(h_parent != h_dst->d_parent); ++ ++ sb = cpg->dentry->d_sb; ++ h_path.mnt = au_sbr_mnt(sb, cpg->bdst); ++ if (do_dt) { ++ h_path.dentry = h_parent; ++ au_dtime_store(&dt, dst_parent, &h_path); ++ } ++ h_path.dentry = h_dst; ++ ++ isreg = 0; ++ isdir = 0; ++ mode = h_inode->i_mode; ++ switch (mode & S_IFMT) { ++ case S_IFREG: ++ isreg = 1; ++ err = vfsub_create(h_dir, &h_path, 0600, /*want_excl*/true); ++ if (!err) ++ err = au_do_cpup_regular(cpg, h_src_attr); ++ break; ++ case S_IFDIR: ++ isdir = 1; ++ err = vfsub_mkdir(h_dir, &h_path, mode); ++ if (!err) ++ err = au_do_cpup_dir(cpg, dst_parent, h_dir, &h_path); ++ break; ++ case S_IFLNK: ++ err = au_do_cpup_symlink(&h_path, h_src, h_dir); ++ break; ++ case S_IFCHR: ++ case S_IFBLK: ++ AuDebugOn(!capable(CAP_MKNOD)); ++ fallthrough; ++ case S_IFIFO: ++ case S_IFSOCK: ++ err = vfsub_mknod(h_dir, &h_path, mode, h_inode->i_rdev); ++ break; ++ default: ++ AuIOErr("Unknown inode type 0%o\n", mode); ++ err = -EIO; ++ } ++ if (!err) ++ err = au_reset_acl(h_dir, &h_path, mode); ++ ++ mnt_flags = au_mntflags(sb); ++ if (!au_opt_test(mnt_flags, UDBA_NONE) ++ && !isdir ++ && au_opt_test(mnt_flags, XINO) ++ && (h_inode->i_nlink == 1 ++ || (h_inode->i_state & I_LINKABLE)) ++ /* todo: unnecessary? */ ++ /* && d_inode(cpg->dentry)->i_nlink == 1 */ ++ && cpg->bdst < cpg->bsrc ++ && !au_ftest_cpup(cpg->flags, KEEPLINO)) ++ au_xino_write(sb, cpg->bsrc, h_inode->i_ino, /*ino*/0); ++ /* ignore this error */ ++ ++ if (!err) { ++ force = 0; ++ if (isreg) { ++ force = !!cpg->len; ++ if (cpg->len == -1) ++ force = !!i_size_read(h_inode); ++ } ++ au_fhsm_wrote(sb, cpg->bdst, force); ++ } ++ ++ if (do_dt) ++ au_dtime_revert(&dt); ++ return err; ++} ++ ++static int au_do_ren_after_cpup(struct au_cp_generic *cpg, struct path *h_path) ++{ ++ int err; ++ struct dentry *dentry, *h_dentry, *h_parent, *parent; ++ struct path h_ppath; ++ struct inode *h_dir; ++ aufs_bindex_t bdst; ++ ++ dentry = cpg->dentry; ++ bdst = cpg->bdst; ++ h_ppath.mnt = au_sbr_mnt(dentry->d_sb, bdst); ++ h_dentry = au_h_dptr(dentry, bdst); ++ if (!au_ftest_cpup(cpg->flags, OVERWRITE)) { ++ dget(h_dentry); ++ au_set_h_dptr(dentry, bdst, NULL); ++ err = au_lkup_neg(dentry, bdst, /*wh*/0); ++ if (!err) ++ h_path->dentry = dget(au_h_dptr(dentry, bdst)); ++ au_set_h_dptr(dentry, bdst, h_dentry); ++ } else { ++ err = 0; ++ parent = dget_parent(dentry); ++ h_ppath.dentry = au_h_dptr(parent, bdst); ++ dput(parent); ++ h_path->dentry = vfsub_lkup_one(&dentry->d_name, &h_ppath); ++ if (IS_ERR(h_path->dentry)) ++ err = PTR_ERR(h_path->dentry); ++ } ++ if (unlikely(err)) ++ goto out; ++ ++ h_parent = h_dentry->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ AuDbg("%pd %pd\n", h_dentry, h_path->dentry); ++ /* no delegation since it is just created */ ++ err = vfsub_rename(h_dir, h_dentry, h_dir, h_path, /*delegated*/NULL, ++ /*flags*/0); ++ dput(h_path->dentry); ++ ++out: ++ return err; ++} ++ ++/* ++ * copyup the @dentry from @bsrc to @bdst. ++ * the caller must set the both of lower dentries. ++ * @len is for truncating when it is -1 copyup the entire file. ++ * in link/rename cases, @dst_parent may be different from the real one. ++ * basic->bsrc can be larger than basic->bdst. ++ * aufs doesn't touch the credential so ++ * security_inode_copy_up{,_xattr}() are unnecessary. ++ */ ++static int au_cpup_single(struct au_cp_generic *cpg, struct dentry *dst_parent) ++{ ++ int err, rerr; ++ aufs_bindex_t old_ibtop; ++ unsigned char isdir, plink; ++ struct dentry *h_src, *h_dst, *h_parent; ++ struct inode *dst_inode, *h_dir, *inode, *delegated, *src_inode; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct path h_src_path; ++ /* to reduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct path h_path; ++ struct au_cpup_reg_attr h_src_attr; ++ } *a; ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ a->h_src_attr.valid = 0; ++ ++ sb = cpg->dentry->d_sb; ++ br = au_sbr(sb, cpg->bdst); ++ a->h_path.mnt = au_br_mnt(br); ++ h_dst = au_h_dptr(cpg->dentry, cpg->bdst); ++ h_parent = h_dst->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ ++ h_src = au_h_dptr(cpg->dentry, cpg->bsrc); ++ inode = d_inode(cpg->dentry); ++ ++ if (!dst_parent) ++ dst_parent = dget_parent(cpg->dentry); ++ else ++ dget(dst_parent); ++ ++ plink = !!au_opt_test(au_mntflags(sb), PLINK); ++ dst_inode = au_h_iptr(inode, cpg->bdst); ++ if (dst_inode) { ++ if (unlikely(!plink)) { ++ err = -EIO; ++ AuIOErr("hi%lu(i%lu) exists on b%d " ++ "but plink is disabled\n", ++ dst_inode->i_ino, inode->i_ino, cpg->bdst); ++ goto out_parent; ++ } ++ ++ if (dst_inode->i_nlink) { ++ const int do_dt = au_ftest_cpup(cpg->flags, DTIME); ++ ++ h_src = au_plink_lkup(inode, cpg->bdst); ++ err = PTR_ERR(h_src); ++ if (IS_ERR(h_src)) ++ goto out_parent; ++ if (unlikely(d_is_negative(h_src))) { ++ err = -EIO; ++ AuIOErr("i%lu exists on b%d " ++ "but not pseudo-linked\n", ++ inode->i_ino, cpg->bdst); ++ dput(h_src); ++ goto out_parent; ++ } ++ ++ if (do_dt) { ++ a->h_path.dentry = h_parent; ++ au_dtime_store(&a->dt, dst_parent, &a->h_path); ++ } ++ ++ a->h_path.dentry = h_dst; ++ delegated = NULL; ++ err = vfsub_link(h_src, h_dir, &a->h_path, &delegated); ++ if (!err && au_ftest_cpup(cpg->flags, RENAME)) ++ err = au_do_ren_after_cpup(cpg, &a->h_path); ++ if (do_dt) ++ au_dtime_revert(&a->dt); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ dput(h_src); ++ goto out_parent; ++ } else ++ /* todo: cpup_wh_file? */ ++ /* udba work */ ++ au_update_ibrange(inode, /*do_put_zero*/1); ++ } ++ ++ isdir = S_ISDIR(inode->i_mode); ++ old_ibtop = au_ibtop(inode); ++ err = cpup_entry(cpg, dst_parent, &a->h_src_attr); ++ if (unlikely(err)) ++ goto out_rev; ++ dst_inode = d_inode(h_dst); ++ inode_lock_nested(dst_inode, AuLsc_I_CHILD2); ++ /* todo: necessary? */ ++ /* au_pin_hdir_unlock(cpg->pin); */ ++ ++ h_src_path.dentry = h_src; ++ h_src_path.mnt = au_sbr_mnt(sb, cpg->bsrc); ++ err = cpup_iattr(cpg->dentry, cpg->bdst, &h_src_path, &a->h_src_attr); ++ if (unlikely(err)) { ++ /* todo: necessary? */ ++ /* au_pin_hdir_relock(cpg->pin); */ /* ignore an error */ ++ inode_unlock(dst_inode); ++ goto out_rev; ++ } ++ ++ if (cpg->bdst < old_ibtop) { ++ if (S_ISREG(inode->i_mode)) { ++ err = au_dy_iaop(inode, cpg->bdst, dst_inode); ++ if (unlikely(err)) { ++ /* ignore an error */ ++ /* au_pin_hdir_relock(cpg->pin); */ ++ inode_unlock(dst_inode); ++ goto out_rev; ++ } ++ } ++ au_set_ibtop(inode, cpg->bdst); ++ } else ++ au_set_ibbot(inode, cpg->bdst); ++ au_set_h_iptr(inode, cpg->bdst, au_igrab(dst_inode), ++ au_hi_flags(inode, isdir)); ++ ++ /* todo: necessary? */ ++ /* err = au_pin_hdir_relock(cpg->pin); */ ++ inode_unlock(dst_inode); ++ if (unlikely(err)) ++ goto out_rev; ++ ++ src_inode = d_inode(h_src); ++ if (!isdir ++ && (src_inode->i_nlink > 1 ++ || src_inode->i_state & I_LINKABLE) ++ && plink) ++ au_plink_append(inode, cpg->bdst, h_dst); ++ ++ if (au_ftest_cpup(cpg->flags, RENAME)) { ++ a->h_path.dentry = h_dst; ++ err = au_do_ren_after_cpup(cpg, &a->h_path); ++ } ++ if (!err) ++ goto out_parent; /* success */ ++ ++ /* revert */ ++out_rev: ++ a->h_path.dentry = h_parent; ++ au_dtime_store(&a->dt, dst_parent, &a->h_path); ++ a->h_path.dentry = h_dst; ++ rerr = 0; ++ if (d_is_positive(h_dst)) { ++ if (!isdir) { ++ /* no delegation since it is just created */ ++ rerr = vfsub_unlink(h_dir, &a->h_path, ++ /*delegated*/NULL, /*force*/0); ++ } else ++ rerr = vfsub_rmdir(h_dir, &a->h_path); ++ } ++ au_dtime_revert(&a->dt); ++ if (rerr) { ++ AuIOErr("failed removing broken entry(%d, %d)\n", err, rerr); ++ err = -EIO; ++ } ++out_parent: ++ dput(dst_parent); ++ au_kfree_rcu(a); ++out: ++ return err; ++} ++ ++#if 0 /* reserved */ ++struct au_cpup_single_args { ++ int *errp; ++ struct au_cp_generic *cpg; ++ struct dentry *dst_parent; ++}; ++ ++static void au_call_cpup_single(void *args) ++{ ++ struct au_cpup_single_args *a = args; ++ ++ au_pin_hdir_acquire_nest(a->cpg->pin); ++ *a->errp = au_cpup_single(a->cpg, a->dst_parent); ++ au_pin_hdir_release(a->cpg->pin); ++} ++#endif ++ ++/* ++ * prevent SIGXFSZ in copy-up. ++ * testing CAP_MKNOD is for generic fs, ++ * but CAP_FSETID is for xfs only, currently. ++ */ ++static int au_cpup_sio_test(struct au_pin *pin, umode_t mode) ++{ ++ int do_sio; ++ struct super_block *sb; ++ struct inode *h_dir; ++ ++ do_sio = 0; ++ sb = au_pinned_parent(pin)->d_sb; ++ if (!au_wkq_test() ++ && (!au_sbi(sb)->si_plink_maint_pid ++ || au_plink_maint(sb, AuLock_NOPLM))) { ++ switch (mode & S_IFMT) { ++ case S_IFREG: ++ /* no condition about RLIMIT_FSIZE and the file size */ ++ do_sio = 1; ++ break; ++ case S_IFCHR: ++ case S_IFBLK: ++ do_sio = !capable(CAP_MKNOD); ++ break; ++ } ++ if (!do_sio) ++ do_sio = ((mode & (S_ISUID | S_ISGID)) ++ && !capable(CAP_FSETID)); ++ /* this workaround may be removed in the future */ ++ if (!do_sio) { ++ h_dir = au_pinned_h_dir(pin); ++ do_sio = h_dir->i_mode & S_ISVTX; ++ } ++ } ++ ++ return do_sio; ++} ++ ++#if 0 /* reserved */ ++int au_sio_cpup_single(struct au_cp_generic *cpg, struct dentry *dst_parent) ++{ ++ int err, wkq_err; ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(cpg->dentry, cpg->bsrc); ++ if (!au_cpup_sio_test(pin, d_inode(h_dentry)->i_mode)) ++ err = au_cpup_single(cpg, dst_parent); ++ else { ++ struct au_cpup_single_args args = { ++ .errp = &err, ++ .cpg = cpg, ++ .dst_parent = dst_parent ++ }; ++ wkq_err = au_wkq_wait(au_call_cpup_single, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ return err; ++} ++#endif ++ ++/* ++ * copyup the @dentry from the first active lower branch to @bdst, ++ * using au_cpup_single(). ++ */ ++static int au_cpup_simple(struct au_cp_generic *cpg) ++{ ++ int err; ++ unsigned int flags_orig; ++ struct dentry *dentry; ++ ++ AuDebugOn(cpg->bsrc < 0); ++ ++ dentry = cpg->dentry; ++ DiMustWriteLock(dentry); ++ ++ err = au_lkup_neg(dentry, cpg->bdst, /*wh*/1); ++ if (!err) { ++ flags_orig = cpg->flags; ++ au_fset_cpup(cpg->flags, RENAME); ++ err = au_cpup_single(cpg, NULL); ++ cpg->flags = flags_orig; ++ if (!err) ++ return 0; /* success */ ++ ++ /* revert */ ++ au_set_h_dptr(dentry, cpg->bdst, NULL); ++ au_set_dbtop(dentry, cpg->bsrc); ++ } ++ ++ return err; ++} ++ ++struct au_cpup_simple_args { ++ int *errp; ++ struct au_cp_generic *cpg; ++}; ++ ++static void au_call_cpup_simple(void *args) ++{ ++ struct au_cpup_simple_args *a = args; ++ ++ au_pin_hdir_acquire_nest(a->cpg->pin); ++ *a->errp = au_cpup_simple(a->cpg); ++ au_pin_hdir_release(a->cpg->pin); ++} ++ ++static int au_do_sio_cpup_simple(struct au_cp_generic *cpg) ++{ ++ int err, wkq_err; ++ struct dentry *dentry, *parent; ++ struct file *h_file; ++ struct inode *h_dir; ++ struct user_namespace *h_userns; ++ ++ dentry = cpg->dentry; ++ h_file = NULL; ++ if (au_ftest_cpup(cpg->flags, HOPEN)) { ++ AuDebugOn(cpg->bsrc < 0); ++ h_file = au_h_open_pre(dentry, cpg->bsrc, /*force_wr*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ } ++ ++ parent = dget_parent(dentry); ++ h_dir = au_h_iptr(d_inode(parent), cpg->bdst); ++ h_userns = au_sbr_userns(dentry->d_sb, cpg->bdst); ++ if (!au_test_h_perm_sio(h_userns, h_dir, MAY_EXEC | MAY_WRITE) ++ && !au_cpup_sio_test(cpg->pin, d_inode(dentry)->i_mode)) ++ err = au_cpup_simple(cpg); ++ else { ++ struct au_cpup_simple_args args = { ++ .errp = &err, ++ .cpg = cpg ++ }; ++ wkq_err = au_wkq_wait(au_call_cpup_simple, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ dput(parent); ++ if (h_file) ++ au_h_open_post(dentry, cpg->bsrc, h_file); ++ ++out: ++ return err; ++} ++ ++int au_sio_cpup_simple(struct au_cp_generic *cpg) ++{ ++ aufs_bindex_t bsrc, bbot; ++ struct dentry *dentry, *h_dentry; ++ ++ if (cpg->bsrc < 0) { ++ dentry = cpg->dentry; ++ bbot = au_dbbot(dentry); ++ for (bsrc = cpg->bdst + 1; bsrc <= bbot; bsrc++) { ++ h_dentry = au_h_dptr(dentry, bsrc); ++ if (h_dentry) { ++ AuDebugOn(d_is_negative(h_dentry)); ++ break; ++ } ++ } ++ AuDebugOn(bsrc > bbot); ++ cpg->bsrc = bsrc; ++ } ++ AuDebugOn(cpg->bsrc <= cpg->bdst); ++ return au_do_sio_cpup_simple(cpg); ++} ++ ++int au_sio_cpdown_simple(struct au_cp_generic *cpg) ++{ ++ AuDebugOn(cpg->bdst <= cpg->bsrc); ++ return au_do_sio_cpup_simple(cpg); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * copyup the deleted file for writing. ++ */ ++static int au_do_cpup_wh(struct au_cp_generic *cpg, struct dentry *wh_dentry, ++ struct file *file) ++{ ++ int err; ++ unsigned int flags_orig; ++ aufs_bindex_t bsrc_orig; ++ struct au_dinfo *dinfo; ++ struct { ++ struct au_hdentry *hd; ++ struct dentry *h_dentry; ++ } hdst, hsrc; ++ ++ dinfo = au_di(cpg->dentry); ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ bsrc_orig = cpg->bsrc; ++ cpg->bsrc = dinfo->di_btop; ++ hdst.hd = au_hdentry(dinfo, cpg->bdst); ++ hdst.h_dentry = hdst.hd->hd_dentry; ++ hdst.hd->hd_dentry = wh_dentry; ++ dinfo->di_btop = cpg->bdst; ++ ++ hsrc.h_dentry = NULL; ++ if (file) { ++ hsrc.hd = au_hdentry(dinfo, cpg->bsrc); ++ hsrc.h_dentry = hsrc.hd->hd_dentry; ++ hsrc.hd->hd_dentry = au_hf_top(file)->f_path.dentry; ++ } ++ flags_orig = cpg->flags; ++ cpg->flags = !AuCpup_DTIME; ++ err = au_cpup_single(cpg, /*h_parent*/NULL); ++ cpg->flags = flags_orig; ++ if (file) { ++ if (!err) ++ err = au_reopen_nondir(file); ++ hsrc.hd->hd_dentry = hsrc.h_dentry; ++ } ++ hdst.hd->hd_dentry = hdst.h_dentry; ++ dinfo->di_btop = cpg->bsrc; ++ cpg->bsrc = bsrc_orig; ++ ++ return err; ++} ++ ++static int au_cpup_wh(struct au_cp_generic *cpg, struct file *file) ++{ ++ int err; ++ aufs_bindex_t bdst; ++ struct au_dtime dt; ++ struct dentry *dentry, *parent, *h_parent, *wh_dentry; ++ struct au_branch *br; ++ struct path h_path; ++ ++ dentry = cpg->dentry; ++ bdst = cpg->bdst; ++ br = au_sbr(dentry->d_sb, bdst); ++ parent = dget_parent(dentry); ++ h_parent = au_h_dptr(parent, bdst); ++ wh_dentry = au_whtmp_lkup(h_parent, br, &dentry->d_name); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out; ++ ++ h_path.dentry = h_parent; ++ h_path.mnt = au_br_mnt(br); ++ au_dtime_store(&dt, parent, &h_path); ++ err = au_do_cpup_wh(cpg, wh_dentry, file); ++ if (unlikely(err)) ++ goto out_wh; ++ ++ dget(wh_dentry); ++ h_path.dentry = wh_dentry; ++ if (!d_is_dir(wh_dentry)) { ++ /* no delegation since it is just created */ ++ err = vfsub_unlink(d_inode(h_parent), &h_path, ++ /*delegated*/NULL, /*force*/0); ++ } else ++ err = vfsub_rmdir(d_inode(h_parent), &h_path); ++ if (unlikely(err)) { ++ AuIOErr("failed remove copied-up tmp file %pd(%d)\n", ++ wh_dentry, err); ++ err = -EIO; ++ } ++ au_dtime_revert(&dt); ++ au_set_hi_wh(d_inode(dentry), bdst, wh_dentry); ++ ++out_wh: ++ dput(wh_dentry); ++out: ++ dput(parent); ++ return err; ++} ++ ++struct au_cpup_wh_args { ++ int *errp; ++ struct au_cp_generic *cpg; ++ struct file *file; ++}; ++ ++static void au_call_cpup_wh(void *args) ++{ ++ struct au_cpup_wh_args *a = args; ++ ++ au_pin_hdir_acquire_nest(a->cpg->pin); ++ *a->errp = au_cpup_wh(a->cpg, a->file); ++ au_pin_hdir_release(a->cpg->pin); ++} ++ ++int au_sio_cpup_wh(struct au_cp_generic *cpg, struct file *file) ++{ ++ int err, wkq_err; ++ aufs_bindex_t bdst; ++ struct dentry *dentry, *parent, *h_orph, *h_parent; ++ struct inode *dir, *h_dir, *h_tmpdir; ++ struct au_wbr *wbr; ++ struct au_pin wh_pin, *pin_orig; ++ struct user_namespace *h_userns; ++ ++ dentry = cpg->dentry; ++ bdst = cpg->bdst; ++ parent = dget_parent(dentry); ++ dir = d_inode(parent); ++ h_orph = NULL; ++ h_parent = NULL; ++ h_dir = au_igrab(au_h_iptr(dir, bdst)); ++ h_tmpdir = h_dir; ++ pin_orig = NULL; ++ if (!h_dir->i_nlink) { ++ wbr = au_sbr(dentry->d_sb, bdst)->br_wbr; ++ h_orph = wbr->wbr_orph; ++ ++ h_parent = dget(au_h_dptr(parent, bdst)); ++ au_set_h_dptr(parent, bdst, dget(h_orph)); ++ h_tmpdir = d_inode(h_orph); ++ au_set_h_iptr(dir, bdst, au_igrab(h_tmpdir), /*flags*/0); ++ ++ inode_lock_nested(h_tmpdir, AuLsc_I_PARENT3); ++ /* todo: au_h_open_pre()? */ ++ ++ pin_orig = cpg->pin; ++ au_pin_init(&wh_pin, dentry, bdst, AuLsc_DI_PARENT, ++ AuLsc_I_PARENT3, cpg->pin->udba, AuPin_DI_LOCKED); ++ cpg->pin = &wh_pin; ++ } ++ ++ h_userns = au_sbr_userns(dentry->d_sb, bdst); ++ if (!au_test_h_perm_sio(h_userns, h_tmpdir, MAY_EXEC | MAY_WRITE) ++ && !au_cpup_sio_test(cpg->pin, d_inode(dentry)->i_mode)) ++ err = au_cpup_wh(cpg, file); ++ else { ++ struct au_cpup_wh_args args = { ++ .errp = &err, ++ .cpg = cpg, ++ .file = file ++ }; ++ wkq_err = au_wkq_wait(au_call_cpup_wh, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ if (h_orph) { ++ inode_unlock(h_tmpdir); ++ /* todo: au_h_open_post()? */ ++ au_set_h_iptr(dir, bdst, au_igrab(h_dir), /*flags*/0); ++ au_set_h_dptr(parent, bdst, h_parent); ++ AuDebugOn(!pin_orig); ++ cpg->pin = pin_orig; ++ } ++ iput(h_dir); ++ dput(parent); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * generic routine for both of copy-up and copy-down. ++ */ ++/* cf. revalidate function in file.c */ ++int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst, ++ int (*cp)(struct dentry *dentry, aufs_bindex_t bdst, ++ struct au_pin *pin, ++ struct dentry *h_parent, void *arg), ++ void *arg) ++{ ++ int err; ++ struct au_pin pin; ++ struct dentry *d, *parent, *h_parent, *real_parent, *h_dentry; ++ ++ err = 0; ++ parent = dget_parent(dentry); ++ if (IS_ROOT(parent)) ++ goto out; ++ ++ au_pin_init(&pin, dentry, bdst, AuLsc_DI_PARENT2, AuLsc_I_PARENT2, ++ au_opt_udba(dentry->d_sb), AuPin_MNT_WRITE); ++ ++ /* do not use au_dpage */ ++ real_parent = parent; ++ while (1) { ++ dput(parent); ++ parent = dget_parent(dentry); ++ h_parent = au_h_dptr(parent, bdst); ++ if (h_parent) ++ goto out; /* success */ ++ ++ /* find top dir which is necessary to cpup */ ++ do { ++ d = parent; ++ dput(parent); ++ parent = dget_parent(d); ++ di_read_lock_parent3(parent, !AuLock_IR); ++ h_parent = au_h_dptr(parent, bdst); ++ di_read_unlock(parent, !AuLock_IR); ++ } while (!h_parent); ++ ++ if (d != real_parent) ++ di_write_lock_child3(d); ++ ++ /* somebody else might create while we were sleeping */ ++ h_dentry = au_h_dptr(d, bdst); ++ if (!h_dentry || d_is_negative(h_dentry)) { ++ if (h_dentry) ++ au_update_dbtop(d); ++ ++ au_pin_set_dentry(&pin, d); ++ err = au_do_pin(&pin); ++ if (!err) { ++ err = cp(d, bdst, &pin, h_parent, arg); ++ au_unpin(&pin); ++ } ++ } ++ ++ if (d != real_parent) ++ di_write_unlock(d); ++ if (unlikely(err)) ++ break; ++ } ++ ++out: ++ dput(parent); ++ return err; ++} ++ ++static int au_cpup_dir(struct dentry *dentry, aufs_bindex_t bdst, ++ struct au_pin *pin, ++ struct dentry *h_parent __maybe_unused, ++ void *arg __maybe_unused) ++{ ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = bdst, ++ .bsrc = -1, ++ .len = 0, ++ .pin = pin, ++ .flags = AuCpup_DTIME ++ }; ++ return au_sio_cpup_simple(&cpg); ++} ++ ++int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst) ++{ ++ return au_cp_dirs(dentry, bdst, au_cpup_dir, NULL); ++} ++ ++int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst) ++{ ++ int err; ++ struct dentry *parent; ++ struct inode *dir; ++ ++ parent = dget_parent(dentry); ++ dir = d_inode(parent); ++ err = 0; ++ if (au_h_iptr(dir, bdst)) ++ goto out; ++ ++ di_read_unlock(parent, AuLock_IR); ++ di_write_lock_parent(parent); ++ /* someone else might change our inode while we were sleeping */ ++ if (!au_h_iptr(dir, bdst)) ++ err = au_cpup_dirs(dentry, bdst); ++ di_downgrade_lock(parent, AuLock_IR); ++ ++out: ++ dput(parent); ++ return err; ++} +diff -Nurp linux-5.15.37/fs/aufs/cpup.h linux-5.15.37-aufs/fs/aufs/cpup.h +--- linux-5.15.37/fs/aufs/cpup.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/cpup.h 2022-04-08 20:22:30.611616426 +0300 +@@ -0,0 +1,87 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * copy-up/down functions ++ */ ++ ++#ifndef __AUFS_CPUP_H__ ++#define __AUFS_CPUP_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++struct inode; ++struct file; ++struct au_pin; ++ ++void au_cpup_attr_flags(struct inode *dst, unsigned int iflags); ++void au_cpup_attr_timesizes(struct inode *inode); ++void au_cpup_attr_nlink(struct inode *inode, int force); ++void au_cpup_attr_changeable(struct inode *inode); ++void au_cpup_igen(struct inode *inode, struct inode *h_inode); ++void au_cpup_attr_all(struct inode *inode, int force); ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_cp_generic { ++ struct dentry *dentry; ++ aufs_bindex_t bdst, bsrc; ++ loff_t len; ++ struct au_pin *pin; ++ unsigned int flags; ++}; ++ ++/* cpup flags */ ++#define AuCpup_DTIME 1 /* do dtime_store/revert */ ++#define AuCpup_KEEPLINO (1 << 1) /* do not clear the lower xino, ++ for link(2) */ ++#define AuCpup_RENAME (1 << 2) /* rename after cpup */ ++#define AuCpup_HOPEN (1 << 3) /* call h_open_pre/post() in ++ cpup */ ++#define AuCpup_OVERWRITE (1 << 4) /* allow overwriting the ++ existing entry */ ++#define AuCpup_RWDST (1 << 5) /* force write target even if ++ the branch is marked as RO */ ++ ++#ifndef CONFIG_AUFS_BR_HFSPLUS ++#undef AuCpup_HOPEN ++#define AuCpup_HOPEN 0 ++#endif ++ ++#define au_ftest_cpup(flags, name) ((flags) & AuCpup_##name) ++#define au_fset_cpup(flags, name) \ ++ do { (flags) |= AuCpup_##name; } while (0) ++#define au_fclr_cpup(flags, name) \ ++ do { (flags) &= ~AuCpup_##name; } while (0) ++ ++int au_copy_file(struct file *dst, struct file *src, loff_t len); ++int au_sio_cpup_simple(struct au_cp_generic *cpg); ++int au_sio_cpdown_simple(struct au_cp_generic *cpg); ++int au_sio_cpup_wh(struct au_cp_generic *cpg, struct file *file); ++ ++int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst, ++ int (*cp)(struct dentry *dentry, aufs_bindex_t bdst, ++ struct au_pin *pin, ++ struct dentry *h_parent, void *arg), ++ void *arg); ++int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst); ++int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* keep timestamps when copyup */ ++struct au_dtime { ++ struct dentry *dt_dentry; ++ struct path dt_h_path; ++ struct timespec64 dt_atime, dt_mtime; ++}; ++void au_dtime_store(struct au_dtime *dt, struct dentry *dentry, ++ struct path *h_path); ++void au_dtime_revert(struct au_dtime *dt); ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_CPUP_H__ */ +diff -Nurp linux-5.15.37/fs/aufs/dbgaufs.c linux-5.15.37-aufs/fs/aufs/dbgaufs.c +--- linux-5.15.37/fs/aufs/dbgaufs.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/dbgaufs.c 2022-04-08 20:22:30.611616426 +0300 +@@ -0,0 +1,513 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * debugfs interface ++ */ ++ ++#include ++#include "aufs.h" ++ ++#ifndef CONFIG_SYSFS ++#error DEBUG_FS depends upon SYSFS ++#endif ++ ++static struct dentry *dbgaufs; ++static const mode_t dbgaufs_mode = 0444; ++ ++/* 20 is max digits length of ulong 64 */ ++struct dbgaufs_arg { ++ int n; ++ char a[20 * 4]; ++}; ++ ++/* ++ * common function for all XINO files ++ */ ++static int dbgaufs_xi_release(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ void *p; ++ ++ p = file->private_data; ++ if (p) { ++ /* this is struct dbgaufs_arg */ ++ AuDebugOn(!au_kfree_sz_test(p)); ++ au_kfree_do_rcu(p); ++ } ++ return 0; ++} ++ ++static int dbgaufs_xi_open(struct file *xf, struct file *file, int do_fcnt, ++ int cnt) ++{ ++ int err; ++ struct kstat st; ++ struct dbgaufs_arg *p; ++ ++ err = -ENOMEM; ++ p = kmalloc(sizeof(*p), GFP_NOFS); ++ if (unlikely(!p)) ++ goto out; ++ ++ err = 0; ++ p->n = 0; ++ file->private_data = p; ++ if (!xf) ++ goto out; ++ ++ err = vfsub_getattr(&xf->f_path, &st); ++ if (!err) { ++ if (do_fcnt) ++ p->n = snprintf ++ (p->a, sizeof(p->a), "%d, %llux%u %lld\n", ++ cnt, st.blocks, st.blksize, ++ (long long)st.size); ++ else ++ p->n = snprintf(p->a, sizeof(p->a), "%llux%u %lld\n", ++ st.blocks, st.blksize, ++ (long long)st.size); ++ AuDebugOn(p->n >= sizeof(p->a)); ++ } else { ++ p->n = snprintf(p->a, sizeof(p->a), "err %d\n", err); ++ err = 0; ++ } ++ ++out: ++ return err; ++} ++ ++static ssize_t dbgaufs_xi_read(struct file *file, char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct dbgaufs_arg *p; ++ ++ p = file->private_data; ++ return simple_read_from_buffer(buf, count, ppos, p->a, p->n); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct dbgaufs_plink_arg { ++ int n; ++ char a[]; ++}; ++ ++static int dbgaufs_plink_release(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ free_page((unsigned long)file->private_data); ++ return 0; ++} ++ ++static int dbgaufs_plink_open(struct inode *inode, struct file *file) ++{ ++ int err, i, limit; ++ unsigned long n, sum; ++ struct dbgaufs_plink_arg *p; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ struct hlist_bl_head *hbl; ++ ++ err = -ENOMEM; ++ p = (void *)get_zeroed_page(GFP_NOFS); ++ if (unlikely(!p)) ++ goto out; ++ ++ err = -EFBIG; ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ if (au_opt_test(au_mntflags(sb), PLINK)) { ++ limit = PAGE_SIZE - sizeof(p->n); ++ ++ /* the number of buckets */ ++ n = snprintf(p->a + p->n, limit, "%d\n", AuPlink_NHASH); ++ p->n += n; ++ limit -= n; ++ ++ sum = 0; ++ for (i = 0, hbl = sbinfo->si_plink; i < AuPlink_NHASH; ++ i++, hbl++) { ++ n = au_hbl_count(hbl); ++ sum += n; ++ ++ n = snprintf(p->a + p->n, limit, "%lu ", n); ++ p->n += n; ++ limit -= n; ++ if (unlikely(limit <= 0)) ++ goto out_free; ++ } ++ p->a[p->n - 1] = '\n'; ++ ++ /* the sum of plinks */ ++ n = snprintf(p->a + p->n, limit, "%lu\n", sum); ++ p->n += n; ++ limit -= n; ++ if (unlikely(limit <= 0)) ++ goto out_free; ++ } else { ++#define str "1\n0\n0\n" ++ p->n = sizeof(str) - 1; ++ strcpy(p->a, str); ++#undef str ++ } ++ si_read_unlock(sb); ++ ++ err = 0; ++ file->private_data = p; ++ goto out; /* success */ ++ ++out_free: ++ free_page((unsigned long)p); ++out: ++ return err; ++} ++ ++static ssize_t dbgaufs_plink_read(struct file *file, char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct dbgaufs_plink_arg *p; ++ ++ p = file->private_data; ++ return simple_read_from_buffer(buf, count, ppos, p->a, p->n); ++} ++ ++static const struct file_operations dbgaufs_plink_fop = { ++ .owner = THIS_MODULE, ++ .open = dbgaufs_plink_open, ++ .release = dbgaufs_plink_release, ++ .read = dbgaufs_plink_read ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int dbgaufs_xib_open(struct inode *inode, struct file *file) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ err = dbgaufs_xi_open(sbinfo->si_xib, file, /*do_fcnt*/0, /*cnt*/0); ++ si_read_unlock(sb); ++ return err; ++} ++ ++static const struct file_operations dbgaufs_xib_fop = { ++ .owner = THIS_MODULE, ++ .open = dbgaufs_xib_open, ++ .release = dbgaufs_xi_release, ++ .read = dbgaufs_xi_read ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define DbgaufsXi_PREFIX "xi" ++ ++static int dbgaufs_xino_open(struct inode *inode, struct file *file) ++{ ++ int err, idx; ++ long l; ++ aufs_bindex_t bindex; ++ char *p, a[sizeof(DbgaufsXi_PREFIX) + 8]; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ struct au_xino *xi; ++ struct file *xf; ++ struct qstr *name; ++ struct au_branch *br; ++ ++ err = -ENOENT; ++ name = &file->f_path.dentry->d_name; ++ if (unlikely(name->len < sizeof(DbgaufsXi_PREFIX) ++ || memcmp(name->name, DbgaufsXi_PREFIX, ++ sizeof(DbgaufsXi_PREFIX) - 1))) ++ goto out; ++ ++ AuDebugOn(name->len >= sizeof(a)); ++ memcpy(a, name->name, name->len); ++ a[name->len] = '\0'; ++ p = strchr(a, '-'); ++ if (p) ++ *p = '\0'; ++ err = kstrtol(a + sizeof(DbgaufsXi_PREFIX) - 1, 10, &l); ++ if (unlikely(err)) ++ goto out; ++ bindex = l; ++ idx = 0; ++ if (p) { ++ err = kstrtol(p + 1, 10, &l); ++ if (unlikely(err)) ++ goto out; ++ idx = l; ++ } ++ ++ err = -ENOENT; ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ if (unlikely(bindex < 0 || bindex > au_sbbot(sb))) ++ goto out_si; ++ br = au_sbr(sb, bindex); ++ xi = br->br_xino; ++ if (unlikely(idx >= xi->xi_nfile)) ++ goto out_si; ++ xf = au_xino_file(xi, idx); ++ if (xf) ++ err = dbgaufs_xi_open(xf, file, /*do_fcnt*/1, ++ au_xino_count(br)); ++ ++out_si: ++ si_read_unlock(sb); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static const struct file_operations dbgaufs_xino_fop = { ++ .owner = THIS_MODULE, ++ .open = dbgaufs_xino_open, ++ .release = dbgaufs_xi_release, ++ .read = dbgaufs_xi_read ++}; ++ ++void dbgaufs_xino_del(struct au_branch *br) ++{ ++ struct dentry *dbgaufs; ++ ++ dbgaufs = br->br_dbgaufs; ++ if (!dbgaufs) ++ return; ++ ++ br->br_dbgaufs = NULL; ++ /* debugfs acquires the parent i_mutex */ ++ lockdep_off(); ++ debugfs_remove(dbgaufs); ++ lockdep_on(); ++} ++ ++void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ aufs_bindex_t bbot; ++ struct au_branch *br; ++ ++ if (!au_sbi(sb)->si_dbgaufs) ++ return; ++ ++ bbot = au_sbbot(sb); ++ for (; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ dbgaufs_xino_del(br); ++ } ++} ++ ++static void dbgaufs_br_do_add(struct super_block *sb, aufs_bindex_t bindex, ++ unsigned int idx, struct dentry *parent, ++ struct au_sbinfo *sbinfo) ++{ ++ struct au_branch *br; ++ struct dentry *d; ++ /* "xi" bindex(5) "-" idx(2) NULL */ ++ char name[sizeof(DbgaufsXi_PREFIX) + 8]; ++ ++ if (!idx) ++ snprintf(name, sizeof(name), DbgaufsXi_PREFIX "%d", bindex); ++ else ++ snprintf(name, sizeof(name), DbgaufsXi_PREFIX "%d-%u", ++ bindex, idx); ++ br = au_sbr(sb, bindex); ++ if (br->br_dbgaufs) { ++ struct qstr qstr = QSTR_INIT(name, strlen(name)); ++ ++ if (!au_qstreq(&br->br_dbgaufs->d_name, &qstr)) { ++ /* debugfs acquires the parent i_mutex */ ++ lockdep_off(); ++ d = debugfs_rename(parent, br->br_dbgaufs, parent, ++ name); ++ lockdep_on(); ++ if (unlikely(!d)) ++ pr_warn("failed renaming %pd/%s, ignored.\n", ++ parent, name); ++ } ++ } else { ++ lockdep_off(); ++ br->br_dbgaufs = debugfs_create_file(name, dbgaufs_mode, parent, ++ sbinfo, &dbgaufs_xino_fop); ++ lockdep_on(); ++ if (unlikely(!br->br_dbgaufs)) ++ pr_warn("failed creating %pd/%s, ignored.\n", ++ parent, name); ++ } ++} ++ ++static void dbgaufs_br_add(struct super_block *sb, aufs_bindex_t bindex, ++ struct dentry *parent, struct au_sbinfo *sbinfo) ++{ ++ struct au_branch *br; ++ struct au_xino *xi; ++ unsigned int u; ++ ++ br = au_sbr(sb, bindex); ++ xi = br->br_xino; ++ for (u = 0; u < xi->xi_nfile; u++) ++ dbgaufs_br_do_add(sb, bindex, u, parent, sbinfo); ++} ++ ++void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex, int topdown) ++{ ++ struct au_sbinfo *sbinfo; ++ struct dentry *parent; ++ aufs_bindex_t bbot; ++ ++ if (!au_opt_test(au_mntflags(sb), XINO)) ++ return; ++ ++ sbinfo = au_sbi(sb); ++ parent = sbinfo->si_dbgaufs; ++ if (!parent) ++ return; ++ ++ bbot = au_sbbot(sb); ++ if (topdown) ++ for (; bindex <= bbot; bindex++) ++ dbgaufs_br_add(sb, bindex, parent, sbinfo); ++ else ++ for (; bbot >= bindex; bbot--) ++ dbgaufs_br_add(sb, bbot, parent, sbinfo); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_EXPORT ++static int dbgaufs_xigen_open(struct inode *inode, struct file *file) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ err = dbgaufs_xi_open(sbinfo->si_xigen, file, /*do_fcnt*/0, /*cnt*/0); ++ si_read_unlock(sb); ++ return err; ++} ++ ++static const struct file_operations dbgaufs_xigen_fop = { ++ .owner = THIS_MODULE, ++ .open = dbgaufs_xigen_open, ++ .release = dbgaufs_xi_release, ++ .read = dbgaufs_xi_read ++}; ++ ++static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo) ++{ ++ int err; ++ ++ /* ++ * This function is a dynamic '__init' function actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++ ++ err = -EIO; ++ sbinfo->si_dbgaufs_xigen = debugfs_create_file ++ ("xigen", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, ++ &dbgaufs_xigen_fop); ++ if (sbinfo->si_dbgaufs_xigen) ++ err = 0; ++ ++ return err; ++} ++#else ++static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo) ++{ ++ return 0; ++} ++#endif /* CONFIG_AUFS_EXPORT */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++void dbgaufs_si_fin(struct au_sbinfo *sbinfo) ++{ ++ /* ++ * This function is a dynamic '__fin' function actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++ ++ debugfs_remove_recursive(sbinfo->si_dbgaufs); ++ sbinfo->si_dbgaufs = NULL; ++} ++ ++int dbgaufs_si_init(struct au_sbinfo *sbinfo) ++{ ++ int err; ++ char name[SysaufsSiNameLen]; ++ ++ /* ++ * This function is a dynamic '__init' function actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++ ++ err = -ENOENT; ++ if (!dbgaufs) { ++ AuErr1("/debug/aufs is uninitialized\n"); ++ goto out; ++ } ++ ++ err = -EIO; ++ sysaufs_name(sbinfo, name); ++ sbinfo->si_dbgaufs = debugfs_create_dir(name, dbgaufs); ++ if (unlikely(!sbinfo->si_dbgaufs)) ++ goto out; ++ ++ /* regardless plink/noplink option */ ++ sbinfo->si_dbgaufs_plink = debugfs_create_file ++ ("plink", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, ++ &dbgaufs_plink_fop); ++ if (unlikely(!sbinfo->si_dbgaufs_plink)) ++ goto out_dir; ++ ++ /* regardless xino/noxino option */ ++ sbinfo->si_dbgaufs_xib = debugfs_create_file ++ ("xib", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, ++ &dbgaufs_xib_fop); ++ if (unlikely(!sbinfo->si_dbgaufs_xib)) ++ goto out_dir; ++ ++ err = dbgaufs_xigen_init(sbinfo); ++ if (!err) ++ goto out; /* success */ ++ ++out_dir: ++ dbgaufs_si_fin(sbinfo); ++out: ++ if (unlikely(err)) ++ pr_err("debugfs/aufs failed\n"); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void dbgaufs_fin(void) ++{ ++ debugfs_remove(dbgaufs); ++} ++ ++int __init dbgaufs_init(void) ++{ ++ int err; ++ ++ err = -EIO; ++ dbgaufs = debugfs_create_dir(AUFS_NAME, NULL); ++ if (dbgaufs) ++ err = 0; ++ return err; ++} +diff -Nurp linux-5.15.37/fs/aufs/dbgaufs.h linux-5.15.37-aufs/fs/aufs/dbgaufs.h +--- linux-5.15.37/fs/aufs/dbgaufs.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/dbgaufs.h 2022-04-08 20:22:30.611616426 +0300 +@@ -0,0 +1,40 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * debugfs interface ++ */ ++ ++#ifndef __DBGAUFS_H__ ++#define __DBGAUFS_H__ ++ ++#ifdef __KERNEL__ ++ ++struct super_block; ++struct au_sbinfo; ++struct au_branch; ++ ++#ifdef CONFIG_DEBUG_FS ++/* dbgaufs.c */ ++void dbgaufs_xino_del(struct au_branch *br); ++void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex); ++void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex, int topdown); ++void dbgaufs_si_fin(struct au_sbinfo *sbinfo); ++int dbgaufs_si_init(struct au_sbinfo *sbinfo); ++void dbgaufs_fin(void); ++int __init dbgaufs_init(void); ++#else ++AuStubVoid(dbgaufs_xino_del, struct au_branch *br) ++AuStubVoid(dbgaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex) ++AuStubVoid(dbgaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex, ++ int topdown) ++AuStubVoid(dbgaufs_si_fin, struct au_sbinfo *sbinfo) ++AuStubInt0(dbgaufs_si_init, struct au_sbinfo *sbinfo) ++AuStubVoid(dbgaufs_fin, void) ++AuStubInt0(__init dbgaufs_init, void) ++#endif /* CONFIG_DEBUG_FS */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __DBGAUFS_H__ */ +diff -Nurp linux-5.15.37/fs/aufs/dcsub.c linux-5.15.37-aufs/fs/aufs/dcsub.c +--- linux-5.15.37/fs/aufs/dcsub.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/dcsub.c 2022-04-08 20:22:30.611616426 +0300 +@@ -0,0 +1,212 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * sub-routines for dentry cache ++ */ ++ ++#include "aufs.h" ++ ++static void au_dpage_free(struct au_dpage *dpage) ++{ ++ int i; ++ struct dentry **p; ++ ++ p = dpage->dentries; ++ for (i = 0; i < dpage->ndentry; i++) ++ dput(*p++); ++ free_page((unsigned long)dpage->dentries); ++} ++ ++int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp) ++{ ++ int err; ++ void *p; ++ ++ err = -ENOMEM; ++ dpages->dpages = kmalloc(sizeof(*dpages->dpages), gfp); ++ if (unlikely(!dpages->dpages)) ++ goto out; ++ ++ p = (void *)__get_free_page(gfp); ++ if (unlikely(!p)) ++ goto out_dpages; ++ ++ dpages->dpages[0].ndentry = 0; ++ dpages->dpages[0].dentries = p; ++ dpages->ndpage = 1; ++ return 0; /* success */ ++ ++out_dpages: ++ au_kfree_try_rcu(dpages->dpages); ++out: ++ return err; ++} ++ ++void au_dpages_free(struct au_dcsub_pages *dpages) ++{ ++ int i; ++ struct au_dpage *p; ++ ++ p = dpages->dpages; ++ for (i = 0; i < dpages->ndpage; i++) ++ au_dpage_free(p++); ++ au_kfree_try_rcu(dpages->dpages); ++} ++ ++static int au_dpages_append(struct au_dcsub_pages *dpages, ++ struct dentry *dentry, gfp_t gfp) ++{ ++ int err, sz; ++ struct au_dpage *dpage; ++ void *p; ++ ++ dpage = dpages->dpages + dpages->ndpage - 1; ++ sz = PAGE_SIZE / sizeof(dentry); ++ if (unlikely(dpage->ndentry >= sz)) { ++ AuLabel(new dpage); ++ err = -ENOMEM; ++ sz = dpages->ndpage * sizeof(*dpages->dpages); ++ p = au_kzrealloc(dpages->dpages, sz, ++ sz + sizeof(*dpages->dpages), gfp, ++ /*may_shrink*/0); ++ if (unlikely(!p)) ++ goto out; ++ ++ dpages->dpages = p; ++ dpage = dpages->dpages + dpages->ndpage; ++ p = (void *)__get_free_page(gfp); ++ if (unlikely(!p)) ++ goto out; ++ ++ dpage->ndentry = 0; ++ dpage->dentries = p; ++ dpages->ndpage++; ++ } ++ ++ AuDebugOn(au_dcount(dentry) <= 0); ++ dpage->dentries[dpage->ndentry++] = dget_dlock(dentry); ++ return 0; /* success */ ++ ++out: ++ return err; ++} ++ ++/* todo: BAD approach */ ++/* copied from linux/fs/dcache.c */ ++enum d_walk_ret { ++ D_WALK_CONTINUE, ++ D_WALK_QUIT, ++ D_WALK_NORETRY, ++ D_WALK_SKIP, ++}; ++ ++extern void d_walk(struct dentry *parent, void *data, ++ enum d_walk_ret (*enter)(void *, struct dentry *)); ++ ++struct ac_dpages_arg { ++ int err; ++ struct au_dcsub_pages *dpages; ++ struct super_block *sb; ++ au_dpages_test test; ++ void *arg; ++}; ++ ++static enum d_walk_ret au_call_dpages_append(void *_arg, struct dentry *dentry) ++{ ++ enum d_walk_ret ret; ++ struct ac_dpages_arg *arg = _arg; ++ ++ ret = D_WALK_CONTINUE; ++ if (dentry->d_sb == arg->sb ++ && !IS_ROOT(dentry) ++ && au_dcount(dentry) > 0 ++ && au_di(dentry) ++ && (!arg->test || arg->test(dentry, arg->arg))) { ++ arg->err = au_dpages_append(arg->dpages, dentry, GFP_ATOMIC); ++ if (unlikely(arg->err)) ++ ret = D_WALK_QUIT; ++ } ++ ++ return ret; ++} ++ ++int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, ++ au_dpages_test test, void *arg) ++{ ++ struct ac_dpages_arg args = { ++ .err = 0, ++ .dpages = dpages, ++ .sb = root->d_sb, ++ .test = test, ++ .arg = arg ++ }; ++ ++ d_walk(root, &args, au_call_dpages_append); ++ ++ return args.err; ++} ++ ++int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry, ++ int do_include, au_dpages_test test, void *arg) ++{ ++ int err; ++ ++ err = 0; ++ write_seqlock(&rename_lock); ++ spin_lock(&dentry->d_lock); ++ if (do_include ++ && au_dcount(dentry) > 0 ++ && (!test || test(dentry, arg))) ++ err = au_dpages_append(dpages, dentry, GFP_ATOMIC); ++ spin_unlock(&dentry->d_lock); ++ if (unlikely(err)) ++ goto out; ++ ++ /* ++ * RCU for vfsmount is unnecessary since this is a traverse in a single ++ * mount ++ */ ++ while (!IS_ROOT(dentry)) { ++ dentry = dentry->d_parent; /* rename_lock is locked */ ++ spin_lock(&dentry->d_lock); ++ if (au_dcount(dentry) > 0 ++ && (!test || test(dentry, arg))) ++ err = au_dpages_append(dpages, dentry, GFP_ATOMIC); ++ spin_unlock(&dentry->d_lock); ++ if (unlikely(err)) ++ break; ++ } ++ ++out: ++ write_sequnlock(&rename_lock); ++ return err; ++} ++ ++static inline int au_dcsub_dpages_aufs(struct dentry *dentry, void *arg) ++{ ++ return au_di(dentry) && dentry->d_sb == arg; ++} ++ ++int au_dcsub_pages_rev_aufs(struct au_dcsub_pages *dpages, ++ struct dentry *dentry, int do_include) ++{ ++ return au_dcsub_pages_rev(dpages, dentry, do_include, ++ au_dcsub_dpages_aufs, dentry->d_sb); ++} ++ ++int au_test_subdir(struct dentry *d1, struct dentry *d2) ++{ ++ struct path path[2] = { ++ { ++ .dentry = d1 ++ }, ++ { ++ .dentry = d2 ++ } ++ }; ++ ++ return path_is_under(path + 0, path + 1); ++} +diff -Nurp linux-5.15.37/fs/aufs/dcsub.h linux-5.15.37-aufs/fs/aufs/dcsub.h +--- linux-5.15.37/fs/aufs/dcsub.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/dcsub.h 2022-04-08 20:22:30.611616426 +0300 +@@ -0,0 +1,124 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * sub-routines for dentry cache ++ */ ++ ++#ifndef __AUFS_DCSUB_H__ ++#define __AUFS_DCSUB_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++ ++struct au_dpage { ++ int ndentry; ++ struct dentry **dentries; ++}; ++ ++struct au_dcsub_pages { ++ int ndpage; ++ struct au_dpage *dpages; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dcsub.c */ ++int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp); ++void au_dpages_free(struct au_dcsub_pages *dpages); ++typedef int (*au_dpages_test)(struct dentry *dentry, void *arg); ++int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, ++ au_dpages_test test, void *arg); ++int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry, ++ int do_include, au_dpages_test test, void *arg); ++int au_dcsub_pages_rev_aufs(struct au_dcsub_pages *dpages, ++ struct dentry *dentry, int do_include); ++int au_test_subdir(struct dentry *d1, struct dentry *d2); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * todo: in linux-3.13, several similar (but faster) helpers are added to ++ * include/linux/dcache.h. Try them (in the future). ++ */ ++ ++static inline int au_d_hashed_positive(struct dentry *d) ++{ ++ int err; ++ struct inode *inode = d_inode(d); ++ ++ err = 0; ++ if (unlikely(d_unhashed(d) ++ || d_is_negative(d) ++ || !inode->i_nlink)) ++ err = -ENOENT; ++ return err; ++} ++ ++static inline int au_d_linkable(struct dentry *d) ++{ ++ int err; ++ struct inode *inode = d_inode(d); ++ ++ err = au_d_hashed_positive(d); ++ if (err ++ && d_is_positive(d) ++ && (inode->i_state & I_LINKABLE)) ++ err = 0; ++ return err; ++} ++ ++static inline int au_d_alive(struct dentry *d) ++{ ++ int err; ++ struct inode *inode; ++ ++ err = 0; ++ if (!IS_ROOT(d)) ++ err = au_d_hashed_positive(d); ++ else { ++ inode = d_inode(d); ++ if (unlikely(d_unlinked(d) ++ || d_is_negative(d) ++ || !inode->i_nlink)) ++ err = -ENOENT; ++ } ++ return err; ++} ++ ++static inline int au_alive_dir(struct dentry *d) ++{ ++ int err; ++ ++ err = au_d_alive(d); ++ if (unlikely(err || IS_DEADDIR(d_inode(d)))) ++ err = -ENOENT; ++ return err; ++} ++ ++static inline int au_qstreq(struct qstr *a, struct qstr *b) ++{ ++ return a->len == b->len ++ && !memcmp(a->name, b->name, a->len); ++} ++ ++/* ++ * by the commit ++ * 360f547 2015-01-25 dcache: let the dentry count go down to zero without ++ * taking d_lock ++ * the type of d_lockref.count became int, but the inlined function d_count() ++ * still returns unsigned int. ++ * I don't know why. Maybe it is for every d_count() users? ++ * Anyway au_dcount() lives on. ++ */ ++static inline int au_dcount(struct dentry *d) ++{ ++ return (int)d_count(d); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DCSUB_H__ */ +diff -Nurp linux-5.15.37/fs/aufs/debug.c linux-5.15.37-aufs/fs/aufs/debug.c +--- linux-5.15.37/fs/aufs/debug.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/debug.c 2022-04-08 20:22:30.611616426 +0300 +@@ -0,0 +1,431 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * debug print functions ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* Returns 0, or -errno. arg is in kp->arg. */ ++static int param_atomic_t_set(const char *val, const struct kernel_param *kp) ++{ ++ int err, n; ++ ++ err = kstrtoint(val, 0, &n); ++ if (!err) { ++ if (n > 0) ++ au_debug_on(); ++ else ++ au_debug_off(); ++ } ++ return err; ++} ++ ++/* Returns length written or -errno. Buffer is 4k (ie. be short!) */ ++static int param_atomic_t_get(char *buffer, const struct kernel_param *kp) ++{ ++ atomic_t *a; ++ ++ a = kp->arg; ++ return sprintf(buffer, "%d", atomic_read(a)); ++} ++ ++static struct kernel_param_ops param_ops_atomic_t = { ++ .set = param_atomic_t_set, ++ .get = param_atomic_t_get ++ /* void (*free)(void *arg) */ ++}; ++ ++atomic_t aufs_debug = ATOMIC_INIT(0); ++MODULE_PARM_DESC(debug, "debug print"); ++module_param_named(debug, aufs_debug, atomic_t, 0664); ++ ++DEFINE_MUTEX(au_dbg_mtx); /* just to serialize the dbg msgs */ ++char *au_plevel = KERN_DEBUG; ++#define dpri(fmt, ...) do { \ ++ if ((au_plevel \ ++ && strcmp(au_plevel, KERN_DEBUG)) \ ++ || au_debug_test()) \ ++ printk("%s" fmt, au_plevel, ##__VA_ARGS__); \ ++} while (0) ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_dpri_whlist(struct au_nhash *whlist) ++{ ++ unsigned long ul, n; ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ ++ n = whlist->nh_num; ++ head = whlist->nh_head; ++ for (ul = 0; ul < n; ul++) { ++ hlist_for_each_entry(pos, head, wh_hash) ++ dpri("b%d, %.*s, %d\n", ++ pos->wh_bindex, ++ pos->wh_str.len, pos->wh_str.name, ++ pos->wh_str.len); ++ head++; ++ } ++} ++ ++void au_dpri_vdir(struct au_vdir *vdir) ++{ ++ unsigned long ul; ++ union au_vdir_deblk_p p; ++ unsigned char *o; ++ ++ if (!vdir || IS_ERR(vdir)) { ++ dpri("err %ld\n", PTR_ERR(vdir)); ++ return; ++ } ++ ++ dpri("deblk %u, nblk %lu, deblk %p, last{%lu, %p}, ver %llu\n", ++ vdir->vd_deblk_sz, vdir->vd_nblk, vdir->vd_deblk, ++ vdir->vd_last.ul, vdir->vd_last.p.deblk, vdir->vd_version); ++ for (ul = 0; ul < vdir->vd_nblk; ul++) { ++ p.deblk = vdir->vd_deblk[ul]; ++ o = p.deblk; ++ dpri("[%lu]: %p\n", ul, o); ++ } ++} ++ ++static int do_pri_inode(aufs_bindex_t bindex, struct inode *inode, int hn, ++ struct dentry *wh) ++{ ++ char *n = NULL; ++ int l = 0; ++ ++ if (!inode || IS_ERR(inode)) { ++ dpri("i%d: err %ld\n", bindex, PTR_ERR(inode)); ++ return -1; ++ } ++ ++ /* the type of i_blocks depends upon CONFIG_LBDAF */ ++ BUILD_BUG_ON(sizeof(inode->i_blocks) != sizeof(unsigned long) ++ && sizeof(inode->i_blocks) != sizeof(u64)); ++ if (wh) { ++ n = (void *)wh->d_name.name; ++ l = wh->d_name.len; ++ } ++ ++ dpri("i%d: %p, i%lu, %s, cnt %d, nl %u, 0%o, sz %llu, blk %llu," ++ " hn %d, ct %lld, np %lu, st 0x%lx, f 0x%x, v %llu, g %x%s%.*s\n", ++ bindex, inode, ++ inode->i_ino, inode->i_sb ? au_sbtype(inode->i_sb) : "??", ++ atomic_read(&inode->i_count), inode->i_nlink, inode->i_mode, ++ i_size_read(inode), (unsigned long long)inode->i_blocks, ++ hn, (long long)timespec64_to_ns(&inode->i_ctime) & 0x0ffff, ++ inode->i_mapping ? inode->i_mapping->nrpages : 0, ++ inode->i_state, inode->i_flags, inode_peek_iversion(inode), ++ inode->i_generation, ++ l ? ", wh " : "", l, n); ++ return 0; ++} ++ ++void au_dpri_inode(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ struct au_hinode *hi; ++ aufs_bindex_t bindex; ++ int err, hn; ++ ++ err = do_pri_inode(-1, inode, -1, NULL); ++ if (err || !au_test_aufs(inode->i_sb) || au_is_bad_inode(inode)) ++ return; ++ ++ iinfo = au_ii(inode); ++ dpri("i-1: btop %d, bbot %d, gen %d\n", ++ iinfo->ii_btop, iinfo->ii_bbot, au_iigen(inode, NULL)); ++ if (iinfo->ii_btop < 0) ++ return; ++ hn = 0; ++ for (bindex = iinfo->ii_btop; bindex <= iinfo->ii_bbot; bindex++) { ++ hi = au_hinode(iinfo, bindex); ++ hn = !!au_hn(hi); ++ do_pri_inode(bindex, hi->hi_inode, hn, hi->hi_whdentry); ++ } ++} ++ ++void au_dpri_dalias(struct inode *inode) ++{ ++ struct dentry *d; ++ ++ spin_lock(&inode->i_lock); ++ hlist_for_each_entry(d, &inode->i_dentry, d_u.d_alias) ++ au_dpri_dentry(d); ++ spin_unlock(&inode->i_lock); ++} ++ ++static int do_pri_dentry(aufs_bindex_t bindex, struct dentry *dentry) ++{ ++ struct dentry *wh = NULL; ++ int hn; ++ struct inode *inode; ++ struct au_iinfo *iinfo; ++ struct au_hinode *hi; ++ ++ if (!dentry || IS_ERR(dentry)) { ++ dpri("d%d: err %ld\n", bindex, PTR_ERR(dentry)); ++ return -1; ++ } ++ /* do not call dget_parent() here */ ++ /* note: access d_xxx without d_lock */ ++ dpri("d%d: %p, %pd2?, %s, cnt %d, flags 0x%x, %shashed\n", ++ bindex, dentry, dentry, ++ dentry->d_sb ? au_sbtype(dentry->d_sb) : "??", ++ au_dcount(dentry), dentry->d_flags, ++ d_unhashed(dentry) ? "un" : ""); ++ hn = -1; ++ inode = NULL; ++ if (d_is_positive(dentry)) ++ inode = d_inode(dentry); ++ if (inode ++ && au_test_aufs(dentry->d_sb) ++ && bindex >= 0 ++ && !au_is_bad_inode(inode)) { ++ iinfo = au_ii(inode); ++ hi = au_hinode(iinfo, bindex); ++ hn = !!au_hn(hi); ++ wh = hi->hi_whdentry; ++ } ++ do_pri_inode(bindex, inode, hn, wh); ++ return 0; ++} ++ ++void au_dpri_dentry(struct dentry *dentry) ++{ ++ struct au_dinfo *dinfo; ++ aufs_bindex_t bindex; ++ int err; ++ ++ err = do_pri_dentry(-1, dentry); ++ if (err || !au_test_aufs(dentry->d_sb)) ++ return; ++ ++ dinfo = au_di(dentry); ++ if (!dinfo) ++ return; ++ dpri("d-1: btop %d, bbot %d, bwh %d, bdiropq %d, gen %d, tmp %d\n", ++ dinfo->di_btop, dinfo->di_bbot, ++ dinfo->di_bwh, dinfo->di_bdiropq, au_digen(dentry), ++ dinfo->di_tmpfile); ++ if (dinfo->di_btop < 0) ++ return; ++ for (bindex = dinfo->di_btop; bindex <= dinfo->di_bbot; bindex++) ++ do_pri_dentry(bindex, au_hdentry(dinfo, bindex)->hd_dentry); ++} ++ ++static int do_pri_file(aufs_bindex_t bindex, struct file *file) ++{ ++ char a[32]; ++ ++ if (!file || IS_ERR(file)) { ++ dpri("f%d: err %ld\n", bindex, PTR_ERR(file)); ++ return -1; ++ } ++ a[0] = 0; ++ if (bindex < 0 ++ && !IS_ERR_OR_NULL(file->f_path.dentry) ++ && au_test_aufs(file->f_path.dentry->d_sb) ++ && au_fi(file)) ++ snprintf(a, sizeof(a), ", gen %d, mmapped %d", ++ au_figen(file), atomic_read(&au_fi(file)->fi_mmapped)); ++ dpri("f%d: mode 0x%x, flags 0%o, cnt %ld, v %llu, pos %llu%s\n", ++ bindex, file->f_mode, file->f_flags, (long)file_count(file), ++ file->f_version, file->f_pos, a); ++ if (!IS_ERR_OR_NULL(file->f_path.dentry)) ++ do_pri_dentry(bindex, file->f_path.dentry); ++ return 0; ++} ++ ++void au_dpri_file(struct file *file) ++{ ++ struct au_finfo *finfo; ++ struct au_fidir *fidir; ++ struct au_hfile *hfile; ++ aufs_bindex_t bindex; ++ int err; ++ ++ err = do_pri_file(-1, file); ++ if (err ++ || IS_ERR_OR_NULL(file->f_path.dentry) ++ || !au_test_aufs(file->f_path.dentry->d_sb)) ++ return; ++ ++ finfo = au_fi(file); ++ if (!finfo) ++ return; ++ if (finfo->fi_btop < 0) ++ return; ++ fidir = finfo->fi_hdir; ++ if (!fidir) ++ do_pri_file(finfo->fi_btop, finfo->fi_htop.hf_file); ++ else ++ for (bindex = finfo->fi_btop; ++ bindex >= 0 && bindex <= fidir->fd_bbot; ++ bindex++) { ++ hfile = fidir->fd_hfile + bindex; ++ do_pri_file(bindex, hfile ? hfile->hf_file : NULL); ++ } ++} ++ ++static int do_pri_br(aufs_bindex_t bindex, struct au_branch *br) ++{ ++ struct vfsmount *mnt; ++ struct super_block *sb; ++ ++ if (!br || IS_ERR(br)) ++ goto out; ++ mnt = au_br_mnt(br); ++ if (!mnt || IS_ERR(mnt)) ++ goto out; ++ sb = mnt->mnt_sb; ++ if (!sb || IS_ERR(sb)) ++ goto out; ++ ++ dpri("s%d: {perm 0x%x, id %d, wbr %p}, " ++ "%s, dev 0x%02x%02x, flags 0x%lx, cnt %d, active %d, " ++ "xino %d\n", ++ bindex, br->br_perm, br->br_id, br->br_wbr, ++ au_sbtype(sb), MAJOR(sb->s_dev), MINOR(sb->s_dev), ++ sb->s_flags, sb->s_count, ++ atomic_read(&sb->s_active), ++ !!au_xino_file(br->br_xino, /*idx*/-1)); ++ return 0; ++ ++out: ++ dpri("s%d: err %ld\n", bindex, PTR_ERR(br)); ++ return -1; ++} ++ ++void au_dpri_sb(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ aufs_bindex_t bindex; ++ int err; ++ /* to reduce stack size */ ++ struct { ++ struct vfsmount mnt; ++ struct au_branch fake; ++ } *a; ++ ++ /* this function can be called from magic sysrq */ ++ a = kzalloc(sizeof(*a), GFP_ATOMIC); ++ if (unlikely(!a)) { ++ dpri("no memory\n"); ++ return; ++ } ++ ++ a->mnt.mnt_sb = sb; ++ a->fake.br_path.mnt = &a->mnt; ++ err = do_pri_br(-1, &a->fake); ++ au_kfree_rcu(a); ++ dpri("dev 0x%x\n", sb->s_dev); ++ if (err || !au_test_aufs(sb)) ++ return; ++ ++ sbinfo = au_sbi(sb); ++ if (!sbinfo) ++ return; ++ dpri("nw %d, gen %u, kobj %d\n", ++ atomic_read(&sbinfo->si_nowait.nw_len), sbinfo->si_generation, ++ kref_read(&sbinfo->si_kobj.kref)); ++ for (bindex = 0; bindex <= sbinfo->si_bbot; bindex++) ++ do_pri_br(bindex, sbinfo->si_branch[0 + bindex]); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void __au_dbg_verify_dinode(struct dentry *dentry, const char *func, int line) ++{ ++ struct inode *h_inode, *inode = d_inode(dentry); ++ struct dentry *h_dentry; ++ aufs_bindex_t bindex, bbot, bi; ++ ++ if (!inode /* || au_di(dentry)->di_lsc == AuLsc_DI_TMP */) ++ return; ++ ++ bbot = au_dbbot(dentry); ++ bi = au_ibbot(inode); ++ if (bi < bbot) ++ bbot = bi; ++ bindex = au_dbtop(dentry); ++ bi = au_ibtop(inode); ++ if (bi > bindex) ++ bindex = bi; ++ ++ for (; bindex <= bbot; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ h_inode = au_h_iptr(inode, bindex); ++ if (unlikely(h_inode != d_inode(h_dentry))) { ++ au_debug_on(); ++ AuDbg("b%d, %s:%d\n", bindex, func, line); ++ AuDbgDentry(dentry); ++ AuDbgInode(inode); ++ au_debug_off(); ++ if (au_test_fuse(h_inode->i_sb)) ++ WARN_ON_ONCE(1); ++ else ++ BUG(); ++ } ++ } ++} ++ ++void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen) ++{ ++ int err, i, j; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ AuDebugOn(err); ++ err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/1); ++ AuDebugOn(err); ++ for (i = dpages.ndpage - 1; !err && i >= 0; i--) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ for (j = dpage->ndentry - 1; !err && j >= 0; j--) ++ AuDebugOn(au_digen_test(dentries[j], sigen)); ++ } ++ au_dpages_free(&dpages); ++} ++ ++void au_dbg_verify_kthread(void) ++{ ++ if (au_wkq_test()) { ++ au_dbg_blocked(); ++ /* ++ * It may be recursive, but udba=notify between two aufs mounts, ++ * where a single ro branch is shared, is not a problem. ++ */ ++ /* WARN_ON(1); */ ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int __init au_debug_init(void) ++{ ++ aufs_bindex_t bindex; ++ struct au_vdir_destr destr; ++ ++ bindex = -1; ++ AuDebugOn(bindex >= 0); ++ ++ destr.len = -1; ++ AuDebugOn(destr.len < NAME_MAX); ++ ++#ifdef CONFIG_4KSTACKS ++ pr_warn("CONFIG_4KSTACKS is defined.\n"); ++#endif ++ ++ return 0; ++} +diff -Nurp linux-5.15.37/fs/aufs/debug.h linux-5.15.37-aufs/fs/aufs/debug.h +--- linux-5.15.37/fs/aufs/debug.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/debug.h 2022-04-08 20:22:30.611616426 +0300 +@@ -0,0 +1,213 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * debug print functions ++ */ ++ ++#ifndef __AUFS_DEBUG_H__ ++#define __AUFS_DEBUG_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_AUFS_DEBUG ++#define AuDebugOn(a) BUG_ON(a) ++ ++/* module parameter */ ++extern atomic_t aufs_debug; ++static inline void au_debug_on(void) ++{ ++ atomic_inc(&aufs_debug); ++} ++static inline void au_debug_off(void) ++{ ++ atomic_dec_if_positive(&aufs_debug); ++} ++ ++static inline int au_debug_test(void) ++{ ++ return atomic_read(&aufs_debug) > 0; ++} ++#else ++#define AuDebugOn(a) do {} while (0) ++AuStubVoid(au_debug_on, void) ++AuStubVoid(au_debug_off, void) ++AuStubInt0(au_debug_test, void) ++#endif /* CONFIG_AUFS_DEBUG */ ++ ++#define param_check_atomic_t(name, p) __param_check(name, p, atomic_t) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* debug print */ ++ ++#define AuDbg(fmt, ...) do { \ ++ if (au_debug_test()) \ ++ pr_debug("DEBUG: " fmt, ##__VA_ARGS__); \ ++} while (0) ++#define AuLabel(l) AuDbg(#l "\n") ++#define AuIOErr(fmt, ...) pr_err("I/O Error, " fmt, ##__VA_ARGS__) ++#define AuWarn1(fmt, ...) do { \ ++ static unsigned char _c; \ ++ if (!_c++) \ ++ pr_warn(fmt, ##__VA_ARGS__); \ ++} while (0) ++ ++#define AuErr1(fmt, ...) do { \ ++ static unsigned char _c; \ ++ if (!_c++) \ ++ pr_err(fmt, ##__VA_ARGS__); \ ++} while (0) ++ ++#define AuIOErr1(fmt, ...) do { \ ++ static unsigned char _c; \ ++ if (!_c++) \ ++ AuIOErr(fmt, ##__VA_ARGS__); \ ++} while (0) ++ ++#define AuUnsupportMsg "This operation is not supported." \ ++ " Please report this application to aufs-users ML." ++#define AuUnsupport(fmt, ...) do { \ ++ pr_err(AuUnsupportMsg "\n" fmt, ##__VA_ARGS__); \ ++ dump_stack(); \ ++} while (0) ++ ++#define AuTraceErr(e) do { \ ++ if (unlikely((e) < 0)) \ ++ AuDbg("err %d\n", (int)(e)); \ ++} while (0) ++ ++#define AuTraceErrPtr(p) do { \ ++ if (IS_ERR(p)) \ ++ AuDbg("err %ld\n", PTR_ERR(p)); \ ++} while (0) ++ ++/* dirty macros for debug print, use with "%.*s" and caution */ ++#define AuLNPair(qstr) (qstr)->len, (qstr)->name ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct dentry; ++#ifdef CONFIG_AUFS_DEBUG ++extern struct mutex au_dbg_mtx; ++extern char *au_plevel; ++struct au_nhash; ++void au_dpri_whlist(struct au_nhash *whlist); ++struct au_vdir; ++void au_dpri_vdir(struct au_vdir *vdir); ++struct inode; ++void au_dpri_inode(struct inode *inode); ++void au_dpri_dalias(struct inode *inode); ++void au_dpri_dentry(struct dentry *dentry); ++struct file; ++void au_dpri_file(struct file *filp); ++struct super_block; ++void au_dpri_sb(struct super_block *sb); ++ ++#define au_dbg_verify_dinode(d) __au_dbg_verify_dinode(d, __func__, __LINE__) ++void __au_dbg_verify_dinode(struct dentry *dentry, const char *func, int line); ++void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen); ++void au_dbg_verify_kthread(void); ++ ++int __init au_debug_init(void); ++ ++#define AuDbgWhlist(w) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#w "\n"); \ ++ au_dpri_whlist(w); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgVdir(v) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#v "\n"); \ ++ au_dpri_vdir(v); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgInode(i) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#i "\n"); \ ++ au_dpri_inode(i); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgDAlias(i) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#i "\n"); \ ++ au_dpri_dalias(i); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgDentry(d) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#d "\n"); \ ++ au_dpri_dentry(d); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgFile(f) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#f "\n"); \ ++ au_dpri_file(f); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgSb(sb) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#sb "\n"); \ ++ au_dpri_sb(sb); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgSym(addr) do { \ ++ char sym[KSYM_SYMBOL_LEN]; \ ++ sprint_symbol(sym, (unsigned long)addr); \ ++ AuDbg("%s\n", sym); \ ++} while (0) ++#else ++AuStubVoid(au_dbg_verify_dinode, struct dentry *dentry) ++AuStubVoid(au_dbg_verify_gen, struct dentry *parent, unsigned int sigen) ++AuStubVoid(au_dbg_verify_kthread, void) ++AuStubInt0(__init au_debug_init, void) ++ ++#define AuDbgWhlist(w) do {} while (0) ++#define AuDbgVdir(v) do {} while (0) ++#define AuDbgInode(i) do {} while (0) ++#define AuDbgDAlias(i) do {} while (0) ++#define AuDbgDentry(d) do {} while (0) ++#define AuDbgFile(f) do {} while (0) ++#define AuDbgSb(sb) do {} while (0) ++#define AuDbgSym(addr) do {} while (0) ++#endif /* CONFIG_AUFS_DEBUG */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_MAGIC_SYSRQ ++int __init au_sysrq_init(void); ++void au_sysrq_fin(void); ++ ++#ifdef CONFIG_HW_CONSOLE ++#define au_dbg_blocked() do { \ ++ WARN_ON(1); \ ++ handle_sysrq('w'); \ ++} while (0) ++#else ++AuStubVoid(au_dbg_blocked, void) ++#endif ++ ++#else ++AuStubInt0(__init au_sysrq_init, void) ++AuStubVoid(au_sysrq_fin, void) ++AuStubVoid(au_dbg_blocked, void) ++#endif /* CONFIG_AUFS_MAGIC_SYSRQ */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DEBUG_H__ */ +diff -Nurp linux-5.15.37/fs/aufs/dentry.c linux-5.15.37-aufs/fs/aufs/dentry.c +--- linux-5.15.37/fs/aufs/dentry.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/dentry.c 2022-04-08 20:22:30.612616475 +0300 +@@ -0,0 +1,1155 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * lookup and dentry operations ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* ++ * returns positive/negative dentry, NULL or an error. ++ * NULL means whiteout-ed or not-found. ++ */ ++static struct dentry* ++au_do_lookup(struct dentry *h_parent, struct dentry *dentry, ++ aufs_bindex_t bindex, struct au_do_lookup_args *args) ++{ ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct au_branch *br; ++ struct user_namespace *h_userns; ++ struct path h_path; ++ int wh_found, opq; ++ unsigned char wh_able; ++ const unsigned char allow_neg = !!au_ftest_lkup(args->flags, ALLOW_NEG); ++ const unsigned char ignore_perm = !!au_ftest_lkup(args->flags, ++ IGNORE_PERM); ++ ++ wh_found = 0; ++ br = au_sbr(dentry->d_sb, bindex); ++ h_path.dentry = h_parent; ++ h_path.mnt = au_br_mnt(br); ++ h_userns = au_br_userns(br); ++ wh_able = !!au_br_whable(br->br_perm); ++ if (wh_able) ++ wh_found = au_wh_test(h_userns, &h_path, &args->whname, ++ ignore_perm); ++ h_dentry = ERR_PTR(wh_found); ++ if (!wh_found) ++ goto real_lookup; ++ if (unlikely(wh_found < 0)) ++ goto out; ++ ++ /* We found a whiteout */ ++ /* au_set_dbbot(dentry, bindex); */ ++ au_set_dbwh(dentry, bindex); ++ if (!allow_neg) ++ return NULL; /* success */ ++ ++real_lookup: ++ if (!ignore_perm) ++ h_dentry = vfsub_lkup_one(args->name, &h_path); ++ else ++ h_dentry = au_sio_lkup_one(h_userns, args->name, &h_path); ++ if (IS_ERR(h_dentry)) { ++ if (PTR_ERR(h_dentry) == -ENAMETOOLONG ++ && !allow_neg) ++ h_dentry = NULL; ++ goto out; ++ } ++ ++ h_inode = d_inode(h_dentry); ++ if (d_is_negative(h_dentry)) { ++ if (!allow_neg) ++ goto out_neg; ++ } else if (wh_found ++ || (args->type && args->type != (h_inode->i_mode & S_IFMT))) ++ goto out_neg; ++ else if (au_ftest_lkup(args->flags, DIRREN) ++ /* && h_inode */ ++ && !au_dr_lkup_h_ino(args, bindex, h_inode->i_ino)) { ++ AuDbg("b%d %pd ignored hi%llu\n", bindex, h_dentry, ++ (unsigned long long)h_inode->i_ino); ++ goto out_neg; ++ } ++ ++ if (au_dbbot(dentry) <= bindex) ++ au_set_dbbot(dentry, bindex); ++ if (au_dbtop(dentry) < 0 || bindex < au_dbtop(dentry)) ++ au_set_dbtop(dentry, bindex); ++ au_set_h_dptr(dentry, bindex, h_dentry); ++ ++ if (!d_is_dir(h_dentry) ++ || !wh_able ++ || (d_really_is_positive(dentry) && !d_is_dir(dentry))) ++ goto out; /* success */ ++ ++ h_path.dentry = h_dentry; ++ inode_lock_shared_nested(h_inode, AuLsc_I_CHILD); ++ opq = au_diropq_test(h_userns, &h_path); ++ inode_unlock_shared(h_inode); ++ if (opq > 0) ++ au_set_dbdiropq(dentry, bindex); ++ else if (unlikely(opq < 0)) { ++ au_set_h_dptr(dentry, bindex, NULL); ++ h_dentry = ERR_PTR(opq); ++ } ++ goto out; ++ ++out_neg: ++ dput(h_dentry); ++ h_dentry = NULL; ++out: ++ return h_dentry; ++} ++ ++static int au_test_shwh(struct super_block *sb, const struct qstr *name) ++{ ++ if (unlikely(!au_opt_test(au_mntflags(sb), SHWH) ++ && !strncmp(name->name, AUFS_WH_PFX, AUFS_WH_PFX_LEN))) ++ return -EPERM; ++ return 0; ++} ++ ++/* ++ * returns the number of lower positive dentries, ++ * otherwise an error. ++ * can be called at unlinking with @type is zero. ++ */ ++int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t btop, ++ unsigned int flags) ++{ ++ int npositive, err; ++ aufs_bindex_t bindex, btail, bdiropq; ++ unsigned char isdir, dirperm1, dirren; ++ struct au_do_lookup_args args = { ++ .flags = flags, ++ .name = &dentry->d_name ++ }; ++ struct dentry *parent; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ err = au_test_shwh(sb, args.name); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_wh_name_alloc(&args.whname, args.name); ++ if (unlikely(err)) ++ goto out; ++ ++ isdir = !!d_is_dir(dentry); ++ dirperm1 = !!au_opt_test(au_mntflags(sb), DIRPERM1); ++ dirren = !!au_opt_test(au_mntflags(sb), DIRREN); ++ if (dirren) ++ au_fset_lkup(args.flags, DIRREN); ++ ++ npositive = 0; ++ parent = dget_parent(dentry); ++ btail = au_dbtaildir(parent); ++ for (bindex = btop; bindex <= btail; bindex++) { ++ struct dentry *h_parent, *h_dentry; ++ struct inode *h_inode, *h_dir; ++ struct au_branch *br; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry) { ++ if (d_is_positive(h_dentry)) ++ npositive++; ++ break; ++ } ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || !d_is_dir(h_parent)) ++ continue; ++ ++ if (dirren) { ++ /* if the inum matches, then use the prepared name */ ++ err = au_dr_lkup_name(&args, bindex); ++ if (unlikely(err)) ++ goto out_parent; ++ } ++ ++ h_dir = d_inode(h_parent); ++ inode_lock_shared_nested(h_dir, AuLsc_I_PARENT); ++ h_dentry = au_do_lookup(h_parent, dentry, bindex, &args); ++ inode_unlock_shared(h_dir); ++ err = PTR_ERR(h_dentry); ++ if (IS_ERR(h_dentry)) ++ goto out_parent; ++ if (h_dentry) ++ au_fclr_lkup(args.flags, ALLOW_NEG); ++ if (dirperm1) ++ au_fset_lkup(args.flags, IGNORE_PERM); ++ ++ if (au_dbwh(dentry) == bindex) ++ break; ++ if (!h_dentry) ++ continue; ++ if (d_is_negative(h_dentry)) ++ continue; ++ h_inode = d_inode(h_dentry); ++ npositive++; ++ if (!args.type) ++ args.type = h_inode->i_mode & S_IFMT; ++ if (args.type != S_IFDIR) ++ break; ++ else if (isdir) { ++ /* the type of lower may be different */ ++ bdiropq = au_dbdiropq(dentry); ++ if (bdiropq >= 0 && bdiropq <= bindex) ++ break; ++ } ++ br = au_sbr(sb, bindex); ++ if (dirren ++ && au_dr_hino_test_add(&br->br_dirren, h_inode->i_ino, ++ /*add_ent*/NULL)) { ++ /* prepare next name to lookup */ ++ err = au_dr_lkup(&args, dentry, bindex); ++ if (unlikely(err)) ++ goto out_parent; ++ } ++ } ++ ++ if (npositive) { ++ AuLabel(positive); ++ au_update_dbtop(dentry); ++ } ++ err = npositive; ++ if (unlikely(!au_opt_test(au_mntflags(sb), UDBA_NONE) ++ && au_dbtop(dentry) < 0)) { ++ err = -EIO; ++ AuIOErr("both of real entry and whiteout found, %pd, err %d\n", ++ dentry, err); ++ } ++ ++out_parent: ++ dput(parent); ++ au_kfree_try_rcu(args.whname.name); ++ if (dirren) ++ au_dr_lkup_fin(&args); ++out: ++ return err; ++} ++ ++struct dentry *au_sio_lkup_one(struct user_namespace *userns, struct qstr *name, ++ struct path *ppath) ++{ ++ struct dentry *dentry; ++ int wkq_err; ++ ++ if (!au_test_h_perm_sio(userns, d_inode(ppath->dentry), MAY_EXEC)) ++ dentry = vfsub_lkup_one(name, ppath); ++ else { ++ struct vfsub_lkup_one_args args = { ++ .errp = &dentry, ++ .name = name, ++ .ppath = ppath ++ }; ++ ++ wkq_err = au_wkq_wait(vfsub_call_lkup_one, &args); ++ if (unlikely(wkq_err)) ++ dentry = ERR_PTR(wkq_err); ++ } ++ ++ return dentry; ++} ++ ++/* ++ * lookup @dentry on @bindex which should be negative. ++ */ ++int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex, int wh) ++{ ++ int err; ++ struct dentry *parent, *h_dentry; ++ struct au_branch *br; ++ struct user_namespace *h_userns; ++ struct path h_ppath; ++ ++ parent = dget_parent(dentry); ++ br = au_sbr(dentry->d_sb, bindex); ++ h_ppath.dentry = au_h_dptr(parent, bindex); ++ h_ppath.mnt = au_br_mnt(br); ++ h_userns = au_br_userns(br); ++ if (wh) ++ h_dentry = au_whtmp_lkup(h_ppath.dentry, br, &dentry->d_name); ++ else ++ h_dentry = au_sio_lkup_one(h_userns, &dentry->d_name, &h_ppath); ++ err = PTR_ERR(h_dentry); ++ if (IS_ERR(h_dentry)) ++ goto out; ++ if (unlikely(d_is_positive(h_dentry))) { ++ err = -EIO; ++ AuIOErr("%pd should be negative on b%d.\n", h_dentry, bindex); ++ dput(h_dentry); ++ goto out; ++ } ++ ++ err = 0; ++ if (bindex < au_dbtop(dentry)) ++ au_set_dbtop(dentry, bindex); ++ if (au_dbbot(dentry) < bindex) ++ au_set_dbbot(dentry, bindex); ++ au_set_h_dptr(dentry, bindex, h_dentry); ++ ++out: ++ dput(parent); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* subset of struct inode */ ++struct au_iattr { ++ unsigned long i_ino; ++ /* unsigned int i_nlink; */ ++ kuid_t i_uid; ++ kgid_t i_gid; ++ u64 i_version; ++/* ++ loff_t i_size; ++ blkcnt_t i_blocks; ++*/ ++ umode_t i_mode; ++}; ++ ++static void au_iattr_save(struct au_iattr *ia, struct inode *h_inode) ++{ ++ ia->i_ino = h_inode->i_ino; ++ /* ia->i_nlink = h_inode->i_nlink; */ ++ ia->i_uid = h_inode->i_uid; ++ ia->i_gid = h_inode->i_gid; ++ ia->i_version = inode_query_iversion(h_inode); ++/* ++ ia->i_size = h_inode->i_size; ++ ia->i_blocks = h_inode->i_blocks; ++*/ ++ ia->i_mode = (h_inode->i_mode & S_IFMT); ++} ++ ++static int au_iattr_test(struct au_iattr *ia, struct inode *h_inode) ++{ ++ return ia->i_ino != h_inode->i_ino ++ /* || ia->i_nlink != h_inode->i_nlink */ ++ || !uid_eq(ia->i_uid, h_inode->i_uid) ++ || !gid_eq(ia->i_gid, h_inode->i_gid) ++ || !inode_eq_iversion(h_inode, ia->i_version) ++/* ++ || ia->i_size != h_inode->i_size ++ || ia->i_blocks != h_inode->i_blocks ++*/ ++ || ia->i_mode != (h_inode->i_mode & S_IFMT); ++} ++ ++static int au_h_verify_dentry(struct dentry *h_dentry, struct dentry *h_parent, ++ struct au_branch *br) ++{ ++ int err; ++ struct au_iattr ia; ++ struct inode *h_inode; ++ struct dentry *h_d; ++ struct super_block *h_sb; ++ struct path h_ppath; ++ ++ err = 0; ++ memset(&ia, -1, sizeof(ia)); ++ h_sb = h_dentry->d_sb; ++ h_inode = NULL; ++ if (d_is_positive(h_dentry)) { ++ h_inode = d_inode(h_dentry); ++ au_iattr_save(&ia, h_inode); ++ } else if (au_test_nfs(h_sb) || au_test_fuse(h_sb)) ++ /* nfs d_revalidate may return 0 for negative dentry */ ++ /* fuse d_revalidate always return 0 for negative dentry */ ++ goto out; ++ ++ /* main purpose is namei.c:cached_lookup() and d_revalidate */ ++ h_ppath.dentry = h_parent; ++ h_ppath.mnt = au_br_mnt(br); ++ h_d = vfsub_lkup_one(&h_dentry->d_name, &h_ppath); ++ err = PTR_ERR(h_d); ++ if (IS_ERR(h_d)) ++ goto out; ++ ++ err = 0; ++ if (unlikely(h_d != h_dentry ++ || d_inode(h_d) != h_inode ++ || (h_inode && au_iattr_test(&ia, h_inode)))) ++ err = au_busy_or_stale(); ++ dput(h_d); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir, ++ struct dentry *h_parent, struct au_branch *br) ++{ ++ int err; ++ ++ err = 0; ++ if (udba == AuOpt_UDBA_REVAL ++ && !au_test_fs_remote(h_dentry->d_sb)) { ++ IMustLock(h_dir); ++ err = (d_inode(h_dentry->d_parent) != h_dir); ++ } else if (udba != AuOpt_UDBA_NONE) ++ err = au_h_verify_dentry(h_dentry, h_parent, br); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_refresh_hdentry(struct dentry *dentry, struct dentry *parent) ++{ ++ int err; ++ aufs_bindex_t new_bindex, bindex, bbot, bwh, bdiropq; ++ struct au_hdentry tmp, *p, *q; ++ struct au_dinfo *dinfo; ++ struct super_block *sb; ++ ++ DiMustWriteLock(dentry); ++ ++ sb = dentry->d_sb; ++ dinfo = au_di(dentry); ++ bbot = dinfo->di_bbot; ++ bwh = dinfo->di_bwh; ++ bdiropq = dinfo->di_bdiropq; ++ bindex = dinfo->di_btop; ++ p = au_hdentry(dinfo, bindex); ++ for (; bindex <= bbot; bindex++, p++) { ++ if (!p->hd_dentry) ++ continue; ++ ++ new_bindex = au_br_index(sb, p->hd_id); ++ if (new_bindex == bindex) ++ continue; ++ ++ if (dinfo->di_bwh == bindex) ++ bwh = new_bindex; ++ if (dinfo->di_bdiropq == bindex) ++ bdiropq = new_bindex; ++ if (new_bindex < 0) { ++ au_hdput(p); ++ p->hd_dentry = NULL; ++ continue; ++ } ++ ++ /* swap two lower dentries, and loop again */ ++ q = au_hdentry(dinfo, new_bindex); ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hd_dentry) { ++ bindex--; ++ p--; ++ } ++ } ++ ++ dinfo->di_bwh = -1; ++ if (bwh >= 0 && bwh <= au_sbbot(sb) && au_sbr_whable(sb, bwh)) ++ dinfo->di_bwh = bwh; ++ ++ dinfo->di_bdiropq = -1; ++ if (bdiropq >= 0 ++ && bdiropq <= au_sbbot(sb) ++ && au_sbr_whable(sb, bdiropq)) ++ dinfo->di_bdiropq = bdiropq; ++ ++ err = -EIO; ++ dinfo->di_btop = -1; ++ dinfo->di_bbot = -1; ++ bbot = au_dbbot(parent); ++ bindex = 0; ++ p = au_hdentry(dinfo, bindex); ++ for (; bindex <= bbot; bindex++, p++) ++ if (p->hd_dentry) { ++ dinfo->di_btop = bindex; ++ break; ++ } ++ ++ if (dinfo->di_btop >= 0) { ++ bindex = bbot; ++ p = au_hdentry(dinfo, bindex); ++ for (; bindex >= 0; bindex--, p--) ++ if (p->hd_dentry) { ++ dinfo->di_bbot = bindex; ++ err = 0; ++ break; ++ } ++ } ++ ++ return err; ++} ++ ++static void au_do_hide(struct dentry *dentry) ++{ ++ struct inode *inode; ++ ++ if (d_really_is_positive(dentry)) { ++ inode = d_inode(dentry); ++ if (!d_is_dir(dentry)) { ++ if (inode->i_nlink && !d_unhashed(dentry)) ++ drop_nlink(inode); ++ } else { ++ clear_nlink(inode); ++ /* stop next lookup */ ++ inode->i_flags |= S_DEAD; ++ } ++ smp_mb(); /* necessary? */ ++ } ++ d_drop(dentry); ++} ++ ++static int au_hide_children(struct dentry *parent) ++{ ++ int err, i, j, ndentry; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry *dentry; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, parent, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ /* in reverse order */ ++ for (i = dpages.ndpage - 1; i >= 0; i--) { ++ dpage = dpages.dpages + i; ++ ndentry = dpage->ndentry; ++ for (j = ndentry - 1; j >= 0; j--) { ++ dentry = dpage->dentries[j]; ++ if (dentry != parent) ++ au_do_hide(dentry); ++ } ++ } ++ ++out_dpages: ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++static void au_hide(struct dentry *dentry) ++{ ++ int err; ++ ++ AuDbgDentry(dentry); ++ if (d_is_dir(dentry)) { ++ /* shrink_dcache_parent(dentry); */ ++ err = au_hide_children(dentry); ++ if (unlikely(err)) ++ AuIOErr("%pd, failed hiding children, ignored %d\n", ++ dentry, err); ++ } ++ au_do_hide(dentry); ++} ++ ++/* ++ * By adding a dirty branch, a cached dentry may be affected in various ways. ++ * ++ * a dirty branch is added ++ * - on the top of layers ++ * - in the middle of layers ++ * - to the bottom of layers ++ * ++ * on the added branch there exists ++ * - a whiteout ++ * - a diropq ++ * - a same named entry ++ * + exist ++ * * negative --> positive ++ * * positive --> positive ++ * - type is unchanged ++ * - type is changed ++ * + doesn't exist ++ * * negative --> negative ++ * * positive --> negative (rejected by au_br_del() for non-dir case) ++ * - none ++ */ ++static int au_refresh_by_dinfo(struct dentry *dentry, struct au_dinfo *dinfo, ++ struct au_dinfo *tmp) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct { ++ struct dentry *dentry; ++ struct inode *inode; ++ mode_t mode; ++ } orig_h, tmp_h = { ++ .dentry = NULL ++ }; ++ struct au_hdentry *hd; ++ struct inode *inode, *h_inode; ++ struct dentry *h_dentry; ++ ++ err = 0; ++ AuDebugOn(dinfo->di_btop < 0); ++ orig_h.mode = 0; ++ orig_h.dentry = au_hdentry(dinfo, dinfo->di_btop)->hd_dentry; ++ orig_h.inode = NULL; ++ if (d_is_positive(orig_h.dentry)) { ++ orig_h.inode = d_inode(orig_h.dentry); ++ orig_h.mode = orig_h.inode->i_mode & S_IFMT; ++ } ++ if (tmp->di_btop >= 0) { ++ tmp_h.dentry = au_hdentry(tmp, tmp->di_btop)->hd_dentry; ++ if (d_is_positive(tmp_h.dentry)) { ++ tmp_h.inode = d_inode(tmp_h.dentry); ++ tmp_h.mode = tmp_h.inode->i_mode & S_IFMT; ++ } ++ } ++ ++ inode = NULL; ++ if (d_really_is_positive(dentry)) ++ inode = d_inode(dentry); ++ if (!orig_h.inode) { ++ AuDbg("negative originally\n"); ++ if (inode) { ++ au_hide(dentry); ++ goto out; ++ } ++ AuDebugOn(inode); ++ AuDebugOn(dinfo->di_btop != dinfo->di_bbot); ++ AuDebugOn(dinfo->di_bdiropq != -1); ++ ++ if (!tmp_h.inode) { ++ AuDbg("negative --> negative\n"); ++ /* should have only one negative lower */ ++ if (tmp->di_btop >= 0 ++ && tmp->di_btop < dinfo->di_btop) { ++ AuDebugOn(tmp->di_btop != tmp->di_bbot); ++ AuDebugOn(dinfo->di_btop != dinfo->di_bbot); ++ au_set_h_dptr(dentry, dinfo->di_btop, NULL); ++ au_di_cp(dinfo, tmp); ++ hd = au_hdentry(tmp, tmp->di_btop); ++ au_set_h_dptr(dentry, tmp->di_btop, ++ dget(hd->hd_dentry)); ++ } ++ au_dbg_verify_dinode(dentry); ++ } else { ++ AuDbg("negative --> positive\n"); ++ /* ++ * similar to the behaviour of creating with bypassing ++ * aufs. ++ * unhash it in order to force an error in the ++ * succeeding create operation. ++ * we should not set S_DEAD here. ++ */ ++ d_drop(dentry); ++ /* au_di_swap(tmp, dinfo); */ ++ au_dbg_verify_dinode(dentry); ++ } ++ } else { ++ AuDbg("positive originally\n"); ++ /* inode may be NULL */ ++ AuDebugOn(inode && (inode->i_mode & S_IFMT) != orig_h.mode); ++ if (!tmp_h.inode) { ++ AuDbg("positive --> negative\n"); ++ /* or bypassing aufs */ ++ au_hide(dentry); ++ if (tmp->di_bwh >= 0 && tmp->di_bwh <= dinfo->di_btop) ++ dinfo->di_bwh = tmp->di_bwh; ++ if (inode) ++ err = au_refresh_hinode_self(inode); ++ au_dbg_verify_dinode(dentry); ++ } else if (orig_h.mode == tmp_h.mode) { ++ AuDbg("positive --> positive, same type\n"); ++ if (!S_ISDIR(orig_h.mode) ++ && dinfo->di_btop > tmp->di_btop) { ++ /* ++ * similar to the behaviour of removing and ++ * creating. ++ */ ++ au_hide(dentry); ++ if (inode) ++ err = au_refresh_hinode_self(inode); ++ au_dbg_verify_dinode(dentry); ++ } else { ++ /* fill empty slots */ ++ if (dinfo->di_btop > tmp->di_btop) ++ dinfo->di_btop = tmp->di_btop; ++ if (dinfo->di_bbot < tmp->di_bbot) ++ dinfo->di_bbot = tmp->di_bbot; ++ dinfo->di_bwh = tmp->di_bwh; ++ dinfo->di_bdiropq = tmp->di_bdiropq; ++ bbot = dinfo->di_bbot; ++ bindex = tmp->di_btop; ++ hd = au_hdentry(tmp, bindex); ++ for (; bindex <= bbot; bindex++, hd++) { ++ if (au_h_dptr(dentry, bindex)) ++ continue; ++ h_dentry = hd->hd_dentry; ++ if (!h_dentry) ++ continue; ++ AuDebugOn(d_is_negative(h_dentry)); ++ h_inode = d_inode(h_dentry); ++ AuDebugOn(orig_h.mode ++ != (h_inode->i_mode ++ & S_IFMT)); ++ au_set_h_dptr(dentry, bindex, ++ dget(h_dentry)); ++ } ++ if (inode) ++ err = au_refresh_hinode(inode, dentry); ++ au_dbg_verify_dinode(dentry); ++ } ++ } else { ++ AuDbg("positive --> positive, different type\n"); ++ /* similar to the behaviour of removing and creating */ ++ au_hide(dentry); ++ if (inode) ++ err = au_refresh_hinode_self(inode); ++ au_dbg_verify_dinode(dentry); ++ } ++ } ++ ++out: ++ return err; ++} ++ ++void au_refresh_dop(struct dentry *dentry, int force_reval) ++{ ++ const struct dentry_operations *dop ++ = force_reval ? &aufs_dop : dentry->d_sb->s_d_op; ++ static const unsigned int mask ++ = DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE; ++ ++ BUILD_BUG_ON(sizeof(mask) != sizeof(dentry->d_flags)); ++ ++ if (dentry->d_op == dop) ++ return; ++ ++ AuDbg("%pd\n", dentry); ++ spin_lock(&dentry->d_lock); ++ if (dop == &aufs_dop) ++ dentry->d_flags |= mask; ++ else ++ dentry->d_flags &= ~mask; ++ dentry->d_op = dop; ++ spin_unlock(&dentry->d_lock); ++} ++ ++int au_refresh_dentry(struct dentry *dentry, struct dentry *parent) ++{ ++ int err, ebrange, nbr; ++ unsigned int sigen; ++ struct au_dinfo *dinfo, *tmp; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ DiMustWriteLock(dentry); ++ AuDebugOn(IS_ROOT(dentry)); ++ AuDebugOn(d_really_is_negative(parent)); ++ ++ sb = dentry->d_sb; ++ sigen = au_sigen(sb); ++ err = au_digen_test(parent, sigen); ++ if (unlikely(err)) ++ goto out; ++ ++ nbr = au_sbbot(sb) + 1; ++ dinfo = au_di(dentry); ++ err = au_di_realloc(dinfo, nbr, /*may_shrink*/0); ++ if (unlikely(err)) ++ goto out; ++ ebrange = au_dbrange_test(dentry); ++ if (!ebrange) ++ ebrange = au_do_refresh_hdentry(dentry, parent); ++ ++ if (d_unhashed(dentry) || ebrange /* || dinfo->di_tmpfile */) { ++ AuDebugOn(au_dbtop(dentry) < 0 && au_dbbot(dentry) >= 0); ++ if (d_really_is_positive(dentry)) { ++ inode = d_inode(dentry); ++ err = au_refresh_hinode_self(inode); ++ } ++ au_dbg_verify_dinode(dentry); ++ if (!err) ++ goto out_dgen; /* success */ ++ goto out; ++ } ++ ++ /* temporary dinfo */ ++ AuDbgDentry(dentry); ++ err = -ENOMEM; ++ tmp = au_di_alloc(sb, AuLsc_DI_TMP); ++ if (unlikely(!tmp)) ++ goto out; ++ au_di_swap(tmp, dinfo); ++ /* returns the number of positive dentries */ ++ /* ++ * if current working dir is removed, it returns an error. ++ * but the dentry is legal. ++ */ ++ err = au_lkup_dentry(dentry, /*btop*/0, AuLkup_ALLOW_NEG); ++ AuDbgDentry(dentry); ++ au_di_swap(tmp, dinfo); ++ if (err == -ENOENT) ++ err = 0; ++ if (err >= 0) { ++ /* compare/refresh by dinfo */ ++ AuDbgDentry(dentry); ++ err = au_refresh_by_dinfo(dentry, dinfo, tmp); ++ au_dbg_verify_dinode(dentry); ++ AuTraceErr(err); ++ } ++ au_di_realloc(dinfo, nbr, /*may_shrink*/1); /* harmless if err */ ++ au_rw_write_unlock(&tmp->di_rwsem); ++ au_di_free(tmp); ++ if (unlikely(err)) ++ goto out; ++ ++out_dgen: ++ au_update_digen(dentry); ++out: ++ if (unlikely(err && !(dentry->d_flags & DCACHE_NFSFS_RENAMED))) { ++ AuIOErr("failed refreshing %pd, %d\n", dentry, err); ++ AuDbgDentry(dentry); ++ } ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_do_h_d_reval(struct dentry *h_dentry, unsigned int flags, ++ struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ int err, valid; ++ ++ err = 0; ++ if (!(h_dentry->d_flags & DCACHE_OP_REVALIDATE)) ++ goto out; ++ ++ AuDbg("b%d\n", bindex); ++ /* ++ * gave up supporting LOOKUP_CREATE/OPEN for lower fs, ++ * due to whiteout and branch permission. ++ */ ++ flags &= ~(/*LOOKUP_PARENT |*/ LOOKUP_OPEN | LOOKUP_CREATE ++ | LOOKUP_FOLLOW | LOOKUP_EXCL); ++ /* it may return tri-state */ ++ valid = h_dentry->d_op->d_revalidate(h_dentry, flags); ++ ++ if (unlikely(valid < 0)) ++ err = valid; ++ else if (!valid) ++ err = -EINVAL; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* todo: remove this */ ++static int h_d_revalidate(struct dentry *dentry, struct inode *inode, ++ unsigned int flags, int do_udba, int dirren) ++{ ++ int err; ++ umode_t mode, h_mode; ++ aufs_bindex_t bindex, btail, btop, ibs, ibe; ++ unsigned char plus, unhashed, is_root, h_plus, h_nfs, tmpfile; ++ struct inode *h_inode, *h_cached_inode; ++ struct dentry *h_dentry; ++ struct qstr *name, *h_name; ++ ++ err = 0; ++ plus = 0; ++ mode = 0; ++ ibs = -1; ++ ibe = -1; ++ unhashed = !!d_unhashed(dentry); ++ is_root = !!IS_ROOT(dentry); ++ name = &dentry->d_name; ++ tmpfile = au_di(dentry)->di_tmpfile; ++ ++ /* ++ * Theoretically, REVAL test should be unnecessary in case of ++ * {FS,I}NOTIFY. ++ * But {fs,i}notify doesn't fire some necessary events, ++ * IN_ATTRIB for atime/nlink/pageio ++ * Let's do REVAL test too. ++ */ ++ if (do_udba && inode) { ++ mode = (inode->i_mode & S_IFMT); ++ plus = (inode->i_nlink > 0); ++ ibs = au_ibtop(inode); ++ ibe = au_ibbot(inode); ++ } ++ ++ btop = au_dbtop(dentry); ++ btail = btop; ++ if (inode && S_ISDIR(inode->i_mode)) ++ btail = au_dbtaildir(dentry); ++ for (bindex = btop; bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ ++ AuDbg("b%d, %pd\n", bindex, h_dentry); ++ h_nfs = !!au_test_nfs(h_dentry->d_sb); ++ spin_lock(&h_dentry->d_lock); ++ h_name = &h_dentry->d_name; ++ if (unlikely(do_udba ++ && !is_root ++ && ((!h_nfs ++ && (unhashed != !!d_unhashed(h_dentry) ++ || (!tmpfile && !dirren ++ && !au_qstreq(name, h_name)) ++ )) ++ || (h_nfs ++ && !(flags & LOOKUP_OPEN) ++ && (h_dentry->d_flags ++ & DCACHE_NFSFS_RENAMED))) ++ )) { ++ int h_unhashed; ++ ++ h_unhashed = d_unhashed(h_dentry); ++ spin_unlock(&h_dentry->d_lock); ++ AuDbg("unhash 0x%x 0x%x, %pd %pd\n", ++ unhashed, h_unhashed, dentry, h_dentry); ++ goto err; ++ } ++ spin_unlock(&h_dentry->d_lock); ++ ++ err = au_do_h_d_reval(h_dentry, flags, dentry, bindex); ++ if (unlikely(err)) ++ /* do not goto err, to keep the errno */ ++ break; ++ ++ /* todo: plink too? */ ++ if (!do_udba) ++ continue; ++ ++ /* UDBA tests */ ++ if (unlikely(!!inode != d_is_positive(h_dentry))) ++ goto err; ++ ++ h_inode = NULL; ++ if (d_is_positive(h_dentry)) ++ h_inode = d_inode(h_dentry); ++ h_plus = plus; ++ h_mode = mode; ++ h_cached_inode = h_inode; ++ if (h_inode) { ++ h_mode = (h_inode->i_mode & S_IFMT); ++ h_plus = (h_inode->i_nlink > 0); ++ } ++ if (inode && ibs <= bindex && bindex <= ibe) ++ h_cached_inode = au_h_iptr(inode, bindex); ++ ++ if (!h_nfs) { ++ if (unlikely(plus != h_plus && !tmpfile)) ++ goto err; ++ } else { ++ if (unlikely(!(h_dentry->d_flags & DCACHE_NFSFS_RENAMED) ++ && !is_root ++ && !IS_ROOT(h_dentry) ++ && unhashed != d_unhashed(h_dentry))) ++ goto err; ++ } ++ if (unlikely(mode != h_mode ++ || h_cached_inode != h_inode)) ++ goto err; ++ continue; ++ ++err: ++ err = -EINVAL; ++ break; ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* todo: consolidate with do_refresh() and au_reval_for_attr() */ ++static int simple_reval_dpath(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ struct dentry *parent; ++ ++ if (!au_digen_test(dentry, sigen)) ++ return 0; ++ ++ parent = dget_parent(dentry); ++ di_read_lock_parent(parent, AuLock_IR); ++ AuDebugOn(au_digen_test(parent, sigen)); ++ au_dbg_verify_gen(parent, sigen); ++ err = au_refresh_dentry(dentry, parent); ++ di_read_unlock(parent, AuLock_IR); ++ dput(parent); ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_reval_dpath(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ struct dentry *d, *parent; ++ ++ if (!au_ftest_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR)) ++ return simple_reval_dpath(dentry, sigen); ++ ++ /* slow loop, keep it simple and stupid */ ++ /* cf: au_cpup_dirs() */ ++ err = 0; ++ parent = NULL; ++ while (au_digen_test(dentry, sigen)) { ++ d = dentry; ++ while (1) { ++ dput(parent); ++ parent = dget_parent(d); ++ if (!au_digen_test(parent, sigen)) ++ break; ++ d = parent; ++ } ++ ++ if (d != dentry) ++ di_write_lock_child2(d); ++ ++ /* someone might update our dentry while we were sleeping */ ++ if (au_digen_test(d, sigen)) { ++ /* ++ * todo: consolidate with simple_reval_dpath(), ++ * do_refresh() and au_reval_for_attr(). ++ */ ++ di_read_lock_parent(parent, AuLock_IR); ++ err = au_refresh_dentry(d, parent); ++ di_read_unlock(parent, AuLock_IR); ++ } ++ ++ if (d != dentry) ++ di_write_unlock(d); ++ dput(parent); ++ if (unlikely(err)) ++ break; ++ } ++ ++ return err; ++} ++ ++/* ++ * if valid returns 1, otherwise 0. ++ */ ++static int aufs_d_revalidate(struct dentry *dentry, unsigned int flags) ++{ ++ int valid, err; ++ unsigned int sigen; ++ unsigned char do_udba, dirren; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ /* todo: support rcu-walk? */ ++ if (flags & LOOKUP_RCU) ++ return -ECHILD; ++ ++ valid = 0; ++ if (unlikely(!au_di(dentry))) ++ goto out; ++ ++ valid = 1; ++ sb = dentry->d_sb; ++ /* ++ * todo: very ugly ++ * i_mutex of parent dir may be held, ++ * but we should not return 'invalid' due to busy. ++ */ ++ err = aufs_read_lock(dentry, AuLock_FLUSH | AuLock_DW | AuLock_NOPLM); ++ if (unlikely(err)) { ++ valid = err; ++ AuTraceErr(err); ++ goto out; ++ } ++ inode = NULL; ++ if (d_really_is_positive(dentry)) ++ inode = d_inode(dentry); ++ if (unlikely(inode && au_is_bad_inode(inode))) { ++ err = -EINVAL; ++ AuTraceErr(err); ++ goto out_dgrade; ++ } ++ if (unlikely(au_dbrange_test(dentry))) { ++ err = -EINVAL; ++ AuTraceErr(err); ++ goto out_dgrade; ++ } ++ ++ sigen = au_sigen(sb); ++ if (au_digen_test(dentry, sigen)) { ++ AuDebugOn(IS_ROOT(dentry)); ++ err = au_reval_dpath(dentry, sigen); ++ if (unlikely(err)) { ++ AuTraceErr(err); ++ goto out_dgrade; ++ } ++ } ++ di_downgrade_lock(dentry, AuLock_IR); ++ ++ err = -EINVAL; ++ if (!(flags & (LOOKUP_OPEN | LOOKUP_EMPTY)) ++ && inode ++ && !(inode->i_state && I_LINKABLE) ++ && (IS_DEADDIR(inode) || !inode->i_nlink)) { ++ AuTraceErr(err); ++ goto out_inval; ++ } ++ ++ do_udba = !au_opt_test(au_mntflags(sb), UDBA_NONE); ++ if (do_udba && inode) { ++ aufs_bindex_t btop = au_ibtop(inode); ++ struct inode *h_inode; ++ ++ if (btop >= 0) { ++ h_inode = au_h_iptr(inode, btop); ++ if (h_inode && au_test_higen(inode, h_inode)) { ++ AuTraceErr(err); ++ goto out_inval; ++ } ++ } ++ } ++ ++ dirren = !!au_opt_test(au_mntflags(sb), DIRREN); ++ err = h_d_revalidate(dentry, inode, flags, do_udba, dirren); ++ if (unlikely(!err && do_udba && au_dbtop(dentry) < 0)) { ++ err = -EIO; ++ AuDbg("both of real entry and whiteout found, %p, err %d\n", ++ dentry, err); ++ } ++ goto out_inval; ++ ++out_dgrade: ++ di_downgrade_lock(dentry, AuLock_IR); ++out_inval: ++ aufs_read_unlock(dentry, AuLock_IR); ++ AuTraceErr(err); ++ valid = !err; ++out: ++ if (!valid) { ++ AuDbg("%pd invalid, %d\n", dentry, valid); ++ d_drop(dentry); ++ } ++ return valid; ++} ++ ++static void aufs_d_release(struct dentry *dentry) ++{ ++ if (au_di(dentry)) { ++ au_di_fin(dentry); ++ au_hn_di_reinit(dentry); ++ } ++} ++ ++const struct dentry_operations aufs_dop = { ++ .d_revalidate = aufs_d_revalidate, ++ .d_weak_revalidate = aufs_d_revalidate, ++ .d_release = aufs_d_release ++}; ++ ++/* aufs_dop without d_revalidate */ ++const struct dentry_operations aufs_dop_noreval = { ++ .d_release = aufs_d_release ++}; +diff -Nurp linux-5.15.37/fs/aufs/dentry.h linux-5.15.37-aufs/fs/aufs/dentry.h +--- linux-5.15.37/fs/aufs/dentry.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/dentry.h 2022-04-08 20:22:30.612616475 +0300 +@@ -0,0 +1,256 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * lookup and dentry operations ++ */ ++ ++#ifndef __AUFS_DENTRY_H__ ++#define __AUFS_DENTRY_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "dirren.h" ++#include "rwsem.h" ++ ++struct au_hdentry { ++ struct dentry *hd_dentry; ++ aufs_bindex_t hd_id; ++}; ++ ++struct au_dinfo { ++ atomic_t di_generation; ++ ++ struct au_rwsem di_rwsem; ++ aufs_bindex_t di_btop, di_bbot, di_bwh, di_bdiropq; ++ unsigned char di_tmpfile; /* to allow the different name */ ++ struct au_hdentry *di_hdentry; ++ struct rcu_head rcu; ++} ____cacheline_aligned_in_smp; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* flags for au_lkup_dentry() */ ++#define AuLkup_ALLOW_NEG 1 ++#define AuLkup_IGNORE_PERM (1 << 1) ++#define AuLkup_DIRREN (1 << 2) ++#define au_ftest_lkup(flags, name) ((flags) & AuLkup_##name) ++#define au_fset_lkup(flags, name) \ ++ do { (flags) |= AuLkup_##name; } while (0) ++#define au_fclr_lkup(flags, name) \ ++ do { (flags) &= ~AuLkup_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_DIRREN ++#undef AuLkup_DIRREN ++#define AuLkup_DIRREN 0 ++#endif ++ ++struct au_do_lookup_args { ++ unsigned int flags; ++ mode_t type; ++ struct qstr whname, *name; ++ struct au_dr_lookup dirren; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dentry.c */ ++extern const struct dentry_operations aufs_dop, aufs_dop_noreval; ++struct au_branch; ++struct dentry *au_sio_lkup_one(struct user_namespace *userns, struct qstr *name, ++ struct path *ppath); ++int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir, ++ struct dentry *h_parent, struct au_branch *br); ++ ++int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t btop, ++ unsigned int flags); ++int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex, int wh); ++int au_refresh_dentry(struct dentry *dentry, struct dentry *parent); ++int au_reval_dpath(struct dentry *dentry, unsigned int sigen); ++void au_refresh_dop(struct dentry *dentry, int force_reval); ++ ++/* dinfo.c */ ++void au_di_init_once(void *_di); ++struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc); ++void au_di_free(struct au_dinfo *dinfo); ++void au_di_swap(struct au_dinfo *a, struct au_dinfo *b); ++void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src); ++int au_di_init(struct dentry *dentry); ++void au_di_fin(struct dentry *dentry); ++int au_di_realloc(struct au_dinfo *dinfo, int nbr, int may_shrink); ++ ++void di_read_lock(struct dentry *d, int flags, unsigned int lsc); ++void di_read_unlock(struct dentry *d, int flags); ++void di_downgrade_lock(struct dentry *d, int flags); ++void di_write_lock(struct dentry *d, unsigned int lsc); ++void di_write_unlock(struct dentry *d); ++void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir); ++void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir); ++void di_write_unlock2(struct dentry *d1, struct dentry *d2); ++ ++struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex); ++struct dentry *au_h_d_alias(struct dentry *dentry, aufs_bindex_t bindex); ++aufs_bindex_t au_dbtail(struct dentry *dentry); ++aufs_bindex_t au_dbtaildir(struct dentry *dentry); ++ ++void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_dentry); ++int au_digen_test(struct dentry *dentry, unsigned int sigen); ++int au_dbrange_test(struct dentry *dentry); ++void au_update_digen(struct dentry *dentry); ++void au_update_dbrange(struct dentry *dentry, int do_put_zero); ++void au_update_dbtop(struct dentry *dentry); ++void au_update_dbbot(struct dentry *dentry); ++int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_dinfo *au_di(struct dentry *dentry) ++{ ++ return dentry->d_fsdata; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock subclass for dinfo */ ++enum { ++ AuLsc_DI_CHILD, /* child first */ ++ AuLsc_DI_CHILD2, /* rename(2), link(2), and cpup at hnotify */ ++ AuLsc_DI_CHILD3, /* copyup dirs */ ++ AuLsc_DI_PARENT, ++ AuLsc_DI_PARENT2, ++ AuLsc_DI_PARENT3, ++ AuLsc_DI_TMP /* temp for replacing dinfo */ ++}; ++ ++/* ++ * di_read_lock_child, di_write_lock_child, ++ * di_read_lock_child2, di_write_lock_child2, ++ * di_read_lock_child3, di_write_lock_child3, ++ * di_read_lock_parent, di_write_lock_parent, ++ * di_read_lock_parent2, di_write_lock_parent2, ++ * di_read_lock_parent3, di_write_lock_parent3, ++ */ ++#define AuReadLockFunc(name, lsc) \ ++static inline void di_read_lock_##name(struct dentry *d, int flags) \ ++{ di_read_lock(d, flags, AuLsc_DI_##lsc); } ++ ++#define AuWriteLockFunc(name, lsc) \ ++static inline void di_write_lock_##name(struct dentry *d) \ ++{ di_write_lock(d, AuLsc_DI_##lsc); } ++ ++#define AuRWLockFuncs(name, lsc) \ ++ AuReadLockFunc(name, lsc) \ ++ AuWriteLockFunc(name, lsc) ++ ++AuRWLockFuncs(child, CHILD); ++AuRWLockFuncs(child2, CHILD2); ++AuRWLockFuncs(child3, CHILD3); ++AuRWLockFuncs(parent, PARENT); ++AuRWLockFuncs(parent2, PARENT2); ++AuRWLockFuncs(parent3, PARENT3); ++ ++#undef AuReadLockFunc ++#undef AuWriteLockFunc ++#undef AuRWLockFuncs ++ ++#define DiMustNoWaiters(d) AuRwMustNoWaiters(&au_di(d)->di_rwsem) ++#define DiMustAnyLock(d) AuRwMustAnyLock(&au_di(d)->di_rwsem) ++#define DiMustWriteLock(d) AuRwMustWriteLock(&au_di(d)->di_rwsem) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* todo: memory barrier? */ ++static inline unsigned int au_digen(struct dentry *d) ++{ ++ return atomic_read(&au_di(d)->di_generation); ++} ++ ++static inline void au_h_dentry_init(struct au_hdentry *hdentry) ++{ ++ hdentry->hd_dentry = NULL; ++} ++ ++static inline struct au_hdentry *au_hdentry(struct au_dinfo *di, ++ aufs_bindex_t bindex) ++{ ++ return di->di_hdentry + bindex; ++} ++ ++static inline void au_hdput(struct au_hdentry *hd) ++{ ++ if (hd) ++ dput(hd->hd_dentry); ++} ++ ++static inline aufs_bindex_t au_dbtop(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_btop; ++} ++ ++static inline aufs_bindex_t au_dbbot(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_bbot; ++} ++ ++static inline aufs_bindex_t au_dbwh(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_bwh; ++} ++ ++static inline aufs_bindex_t au_dbdiropq(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_bdiropq; ++} ++ ++/* todo: hard/soft set? */ ++static inline void au_set_dbtop(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ au_di(dentry)->di_btop = bindex; ++} ++ ++static inline void au_set_dbbot(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ au_di(dentry)->di_bbot = bindex; ++} ++ ++static inline void au_set_dbwh(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ /* dbwh can be outside of btop - bbot range */ ++ au_di(dentry)->di_bwh = bindex; ++} ++ ++static inline void au_set_dbdiropq(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ au_di(dentry)->di_bdiropq = bindex; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_HNOTIFY ++static inline void au_digen_dec(struct dentry *d) ++{ ++ atomic_dec(&au_di(d)->di_generation); ++} ++ ++static inline void au_hn_di_reinit(struct dentry *dentry) ++{ ++ dentry->d_fsdata = NULL; ++} ++#else ++AuStubVoid(au_hn_di_reinit, struct dentry *dentry __maybe_unused) ++#endif /* CONFIG_AUFS_HNOTIFY */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DENTRY_H__ */ +diff -Nurp linux-5.15.37/fs/aufs/dinfo.c linux-5.15.37-aufs/fs/aufs/dinfo.c +--- linux-5.15.37/fs/aufs/dinfo.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/dinfo.c 2022-04-08 20:22:30.612616475 +0300 +@@ -0,0 +1,541 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * dentry private data ++ */ ++ ++#include "aufs.h" ++ ++void au_di_init_once(void *_dinfo) ++{ ++ struct au_dinfo *dinfo = _dinfo; ++ ++ au_rw_init(&dinfo->di_rwsem); ++} ++ ++struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc) ++{ ++ struct au_dinfo *dinfo; ++ int nbr, i; ++ ++ dinfo = au_cache_alloc_dinfo(); ++ if (unlikely(!dinfo)) ++ goto out; ++ ++ nbr = au_sbbot(sb) + 1; ++ if (nbr <= 0) ++ nbr = 1; ++ dinfo->di_hdentry = kcalloc(nbr, sizeof(*dinfo->di_hdentry), GFP_NOFS); ++ if (dinfo->di_hdentry) { ++ au_rw_write_lock_nested(&dinfo->di_rwsem, lsc); ++ dinfo->di_btop = -1; ++ dinfo->di_bbot = -1; ++ dinfo->di_bwh = -1; ++ dinfo->di_bdiropq = -1; ++ dinfo->di_tmpfile = 0; ++ for (i = 0; i < nbr; i++) ++ dinfo->di_hdentry[i].hd_id = -1; ++ goto out; ++ } ++ ++ au_cache_free_dinfo(dinfo); ++ dinfo = NULL; ++ ++out: ++ return dinfo; ++} ++ ++void au_di_free(struct au_dinfo *dinfo) ++{ ++ struct au_hdentry *p; ++ aufs_bindex_t bbot, bindex; ++ ++ /* dentry may not be revalidated */ ++ bindex = dinfo->di_btop; ++ if (bindex >= 0) { ++ bbot = dinfo->di_bbot; ++ p = au_hdentry(dinfo, bindex); ++ while (bindex++ <= bbot) ++ au_hdput(p++); ++ } ++ au_kfree_try_rcu(dinfo->di_hdentry); ++ au_cache_free_dinfo(dinfo); ++} ++ ++void au_di_swap(struct au_dinfo *a, struct au_dinfo *b) ++{ ++ struct au_hdentry *p; ++ aufs_bindex_t bi; ++ ++ AuRwMustWriteLock(&a->di_rwsem); ++ AuRwMustWriteLock(&b->di_rwsem); ++ ++#define DiSwap(v, name) \ ++ do { \ ++ v = a->di_##name; \ ++ a->di_##name = b->di_##name; \ ++ b->di_##name = v; \ ++ } while (0) ++ ++ DiSwap(p, hdentry); ++ DiSwap(bi, btop); ++ DiSwap(bi, bbot); ++ DiSwap(bi, bwh); ++ DiSwap(bi, bdiropq); ++ /* smp_mb(); */ ++ ++#undef DiSwap ++} ++ ++void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src) ++{ ++ AuRwMustWriteLock(&dst->di_rwsem); ++ AuRwMustWriteLock(&src->di_rwsem); ++ ++ dst->di_btop = src->di_btop; ++ dst->di_bbot = src->di_bbot; ++ dst->di_bwh = src->di_bwh; ++ dst->di_bdiropq = src->di_bdiropq; ++ /* smp_mb(); */ ++} ++ ++int au_di_init(struct dentry *dentry) ++{ ++ int err; ++ struct super_block *sb; ++ struct au_dinfo *dinfo; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ dinfo = au_di_alloc(sb, AuLsc_DI_CHILD); ++ if (dinfo) { ++ atomic_set(&dinfo->di_generation, au_sigen(sb)); ++ /* smp_mb(); */ /* atomic_set */ ++ dentry->d_fsdata = dinfo; ++ } else ++ err = -ENOMEM; ++ ++ return err; ++} ++ ++void au_di_fin(struct dentry *dentry) ++{ ++ struct au_dinfo *dinfo; ++ ++ dinfo = au_di(dentry); ++ AuRwDestroy(&dinfo->di_rwsem); ++ au_di_free(dinfo); ++} ++ ++int au_di_realloc(struct au_dinfo *dinfo, int nbr, int may_shrink) ++{ ++ int err, sz; ++ struct au_hdentry *hdp; ++ ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ err = -ENOMEM; ++ sz = sizeof(*hdp) * (dinfo->di_bbot + 1); ++ if (!sz) ++ sz = sizeof(*hdp); ++ hdp = au_kzrealloc(dinfo->di_hdentry, sz, sizeof(*hdp) * nbr, GFP_NOFS, ++ may_shrink); ++ if (hdp) { ++ dinfo->di_hdentry = hdp; ++ err = 0; ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void do_ii_write_lock(struct inode *inode, unsigned int lsc) ++{ ++ switch (lsc) { ++ case AuLsc_DI_CHILD: ++ ii_write_lock_child(inode); ++ break; ++ case AuLsc_DI_CHILD2: ++ ii_write_lock_child2(inode); ++ break; ++ case AuLsc_DI_CHILD3: ++ ii_write_lock_child3(inode); ++ break; ++ case AuLsc_DI_PARENT: ++ ii_write_lock_parent(inode); ++ break; ++ case AuLsc_DI_PARENT2: ++ ii_write_lock_parent2(inode); ++ break; ++ case AuLsc_DI_PARENT3: ++ ii_write_lock_parent3(inode); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++static void do_ii_read_lock(struct inode *inode, unsigned int lsc) ++{ ++ switch (lsc) { ++ case AuLsc_DI_CHILD: ++ ii_read_lock_child(inode); ++ break; ++ case AuLsc_DI_CHILD2: ++ ii_read_lock_child2(inode); ++ break; ++ case AuLsc_DI_CHILD3: ++ ii_read_lock_child3(inode); ++ break; ++ case AuLsc_DI_PARENT: ++ ii_read_lock_parent(inode); ++ break; ++ case AuLsc_DI_PARENT2: ++ ii_read_lock_parent2(inode); ++ break; ++ case AuLsc_DI_PARENT3: ++ ii_read_lock_parent3(inode); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++void di_read_lock(struct dentry *d, int flags, unsigned int lsc) ++{ ++ struct inode *inode; ++ ++ au_rw_read_lock_nested(&au_di(d)->di_rwsem, lsc); ++ if (d_really_is_positive(d)) { ++ inode = d_inode(d); ++ if (au_ftest_lock(flags, IW)) ++ do_ii_write_lock(inode, lsc); ++ else if (au_ftest_lock(flags, IR)) ++ do_ii_read_lock(inode, lsc); ++ } ++} ++ ++void di_read_unlock(struct dentry *d, int flags) ++{ ++ struct inode *inode; ++ ++ if (d_really_is_positive(d)) { ++ inode = d_inode(d); ++ if (au_ftest_lock(flags, IW)) { ++ au_dbg_verify_dinode(d); ++ ii_write_unlock(inode); ++ } else if (au_ftest_lock(flags, IR)) { ++ au_dbg_verify_dinode(d); ++ ii_read_unlock(inode); ++ } ++ } ++ au_rw_read_unlock(&au_di(d)->di_rwsem); ++} ++ ++void di_downgrade_lock(struct dentry *d, int flags) ++{ ++ if (d_really_is_positive(d) && au_ftest_lock(flags, IR)) ++ ii_downgrade_lock(d_inode(d)); ++ au_rw_dgrade_lock(&au_di(d)->di_rwsem); ++} ++ ++void di_write_lock(struct dentry *d, unsigned int lsc) ++{ ++ au_rw_write_lock_nested(&au_di(d)->di_rwsem, lsc); ++ if (d_really_is_positive(d)) ++ do_ii_write_lock(d_inode(d), lsc); ++} ++ ++void di_write_unlock(struct dentry *d) ++{ ++ au_dbg_verify_dinode(d); ++ if (d_really_is_positive(d)) ++ ii_write_unlock(d_inode(d)); ++ au_rw_write_unlock(&au_di(d)->di_rwsem); ++} ++ ++void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir) ++{ ++ AuDebugOn(d1 == d2 ++ || d_inode(d1) == d_inode(d2) ++ || d1->d_sb != d2->d_sb); ++ ++ if ((isdir && au_test_subdir(d1, d2)) ++ || d1 < d2) { ++ di_write_lock_child(d1); ++ di_write_lock_child2(d2); ++ } else { ++ di_write_lock_child(d2); ++ di_write_lock_child2(d1); ++ } ++} ++ ++void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir) ++{ ++ AuDebugOn(d1 == d2 ++ || d_inode(d1) == d_inode(d2) ++ || d1->d_sb != d2->d_sb); ++ ++ if ((isdir && au_test_subdir(d1, d2)) ++ || d1 < d2) { ++ di_write_lock_parent(d1); ++ di_write_lock_parent2(d2); ++ } else { ++ di_write_lock_parent(d2); ++ di_write_lock_parent2(d1); ++ } ++} ++ ++void di_write_unlock2(struct dentry *d1, struct dentry *d2) ++{ ++ di_write_unlock(d1); ++ if (d_inode(d1) == d_inode(d2)) ++ au_rw_write_unlock(&au_di(d2)->di_rwsem); ++ else ++ di_write_unlock(d2); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ struct dentry *d; ++ ++ DiMustAnyLock(dentry); ++ ++ if (au_dbtop(dentry) < 0 || bindex < au_dbtop(dentry)) ++ return NULL; ++ AuDebugOn(bindex < 0); ++ d = au_hdentry(au_di(dentry), bindex)->hd_dentry; ++ AuDebugOn(d && au_dcount(d) <= 0); ++ return d; ++} ++ ++/* ++ * extended version of au_h_dptr(). ++ * returns a hashed and positive (or linkable) h_dentry in bindex, NULL, or ++ * error. ++ */ ++struct dentry *au_h_d_alias(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ struct dentry *h_dentry; ++ struct inode *inode, *h_inode; ++ ++ AuDebugOn(d_really_is_negative(dentry)); ++ ++ h_dentry = NULL; ++ if (au_dbtop(dentry) <= bindex ++ && bindex <= au_dbbot(dentry)) ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && !au_d_linkable(h_dentry)) { ++ dget(h_dentry); ++ goto out; /* success */ ++ } ++ ++ inode = d_inode(dentry); ++ AuDebugOn(bindex < au_ibtop(inode)); ++ AuDebugOn(au_ibbot(inode) < bindex); ++ h_inode = au_h_iptr(inode, bindex); ++ h_dentry = d_find_alias(h_inode); ++ if (h_dentry) { ++ if (!IS_ERR(h_dentry)) { ++ if (!au_d_linkable(h_dentry)) ++ goto out; /* success */ ++ dput(h_dentry); ++ } else ++ goto out; ++ } ++ ++ if (au_opt_test(au_mntflags(dentry->d_sb), PLINK)) { ++ h_dentry = au_plink_lkup(inode, bindex); ++ AuDebugOn(!h_dentry); ++ if (!IS_ERR(h_dentry)) { ++ if (!au_d_hashed_positive(h_dentry)) ++ goto out; /* success */ ++ dput(h_dentry); ++ h_dentry = NULL; ++ } ++ } ++ ++out: ++ AuDbgDentry(h_dentry); ++ return h_dentry; ++} ++ ++aufs_bindex_t au_dbtail(struct dentry *dentry) ++{ ++ aufs_bindex_t bbot, bwh; ++ ++ bbot = au_dbbot(dentry); ++ if (0 <= bbot) { ++ bwh = au_dbwh(dentry); ++ if (!bwh) ++ return bwh; ++ if (0 < bwh && bwh < bbot) ++ return bwh - 1; ++ } ++ return bbot; ++} ++ ++aufs_bindex_t au_dbtaildir(struct dentry *dentry) ++{ ++ aufs_bindex_t bbot, bopq; ++ ++ bbot = au_dbtail(dentry); ++ if (0 <= bbot) { ++ bopq = au_dbdiropq(dentry); ++ if (0 <= bopq && bopq < bbot) ++ bbot = bopq; ++ } ++ return bbot; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_dentry) ++{ ++ struct au_dinfo *dinfo; ++ struct au_hdentry *hd; ++ struct au_branch *br; ++ ++ DiMustWriteLock(dentry); ++ ++ dinfo = au_di(dentry); ++ hd = au_hdentry(dinfo, bindex); ++ au_hdput(hd); ++ hd->hd_dentry = h_dentry; ++ if (h_dentry) { ++ br = au_sbr(dentry->d_sb, bindex); ++ hd->hd_id = br->br_id; ++ } ++} ++ ++int au_dbrange_test(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t btop, bbot; ++ ++ err = 0; ++ btop = au_dbtop(dentry); ++ bbot = au_dbbot(dentry); ++ if (btop >= 0) ++ AuDebugOn(bbot < 0 && btop > bbot); ++ else { ++ err = -EIO; ++ AuDebugOn(bbot >= 0); ++ } ++ ++ return err; ++} ++ ++int au_digen_test(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ ++ err = 0; ++ if (unlikely(au_digen(dentry) != sigen ++ || au_iigen_test(d_inode(dentry), sigen))) ++ err = -EIO; ++ ++ return err; ++} ++ ++void au_update_digen(struct dentry *dentry) ++{ ++ atomic_set(&au_di(dentry)->di_generation, au_sigen(dentry->d_sb)); ++ /* smp_mb(); */ /* atomic_set */ ++} ++ ++void au_update_dbrange(struct dentry *dentry, int do_put_zero) ++{ ++ struct au_dinfo *dinfo; ++ struct dentry *h_d; ++ struct au_hdentry *hdp; ++ aufs_bindex_t bindex, bbot; ++ ++ DiMustWriteLock(dentry); ++ ++ dinfo = au_di(dentry); ++ if (!dinfo || dinfo->di_btop < 0) ++ return; ++ ++ if (do_put_zero) { ++ bbot = dinfo->di_bbot; ++ bindex = dinfo->di_btop; ++ hdp = au_hdentry(dinfo, bindex); ++ for (; bindex <= bbot; bindex++, hdp++) { ++ h_d = hdp->hd_dentry; ++ if (h_d && d_is_negative(h_d)) ++ au_set_h_dptr(dentry, bindex, NULL); ++ } ++ } ++ ++ dinfo->di_btop = 0; ++ hdp = au_hdentry(dinfo, dinfo->di_btop); ++ for (; dinfo->di_btop <= dinfo->di_bbot; dinfo->di_btop++, hdp++) ++ if (hdp->hd_dentry) ++ break; ++ if (dinfo->di_btop > dinfo->di_bbot) { ++ dinfo->di_btop = -1; ++ dinfo->di_bbot = -1; ++ return; ++ } ++ ++ hdp = au_hdentry(dinfo, dinfo->di_bbot); ++ for (; dinfo->di_bbot >= 0; dinfo->di_bbot--, hdp--) ++ if (hdp->hd_dentry) ++ break; ++ AuDebugOn(dinfo->di_btop > dinfo->di_bbot || dinfo->di_bbot < 0); ++} ++ ++void au_update_dbtop(struct dentry *dentry) ++{ ++ aufs_bindex_t bindex, bbot; ++ struct dentry *h_dentry; ++ ++ bbot = au_dbbot(dentry); ++ for (bindex = au_dbtop(dentry); bindex <= bbot; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ if (d_is_positive(h_dentry)) { ++ au_set_dbtop(dentry, bindex); ++ return; ++ } ++ au_set_h_dptr(dentry, bindex, NULL); ++ } ++} ++ ++void au_update_dbbot(struct dentry *dentry) ++{ ++ aufs_bindex_t bindex, btop; ++ struct dentry *h_dentry; ++ ++ btop = au_dbtop(dentry); ++ for (bindex = au_dbbot(dentry); bindex >= btop; bindex--) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ if (d_is_positive(h_dentry)) { ++ au_set_dbbot(dentry, bindex); ++ return; ++ } ++ au_set_h_dptr(dentry, bindex, NULL); ++ } ++} ++ ++int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry) ++{ ++ aufs_bindex_t bindex, bbot; ++ ++ bbot = au_dbbot(dentry); ++ for (bindex = au_dbtop(dentry); bindex <= bbot; bindex++) ++ if (au_h_dptr(dentry, bindex) == h_dentry) ++ return bindex; ++ return -1; ++} +diff -Nurp linux-5.15.37/fs/aufs/dir.c linux-5.15.37-aufs/fs/aufs/dir.c +--- linux-5.15.37/fs/aufs/dir.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/dir.c 2022-04-08 20:22:30.612616475 +0300 +@@ -0,0 +1,752 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * directory operations ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++void au_add_nlink(struct inode *dir, struct inode *h_dir) ++{ ++ unsigned int nlink; ++ ++ AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode)); ++ ++ nlink = dir->i_nlink; ++ nlink += h_dir->i_nlink - 2; ++ if (h_dir->i_nlink < 2) ++ nlink += 2; ++ smp_mb(); /* for i_nlink */ ++ /* 0 can happen in revaliding */ ++ set_nlink(dir, nlink); ++} ++ ++void au_sub_nlink(struct inode *dir, struct inode *h_dir) ++{ ++ unsigned int nlink; ++ ++ AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode)); ++ ++ nlink = dir->i_nlink; ++ nlink -= h_dir->i_nlink - 2; ++ if (h_dir->i_nlink < 2) ++ nlink -= 2; ++ smp_mb(); /* for i_nlink */ ++ /* nlink == 0 means the branch-fs is broken */ ++ set_nlink(dir, nlink); ++} ++ ++loff_t au_dir_size(struct file *file, struct dentry *dentry) ++{ ++ loff_t sz; ++ aufs_bindex_t bindex, bbot; ++ struct file *h_file; ++ struct dentry *h_dentry; ++ ++ sz = 0; ++ if (file) { ++ AuDebugOn(!d_is_dir(file->f_path.dentry)); ++ ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); ++ bindex <= bbot && sz < KMALLOC_MAX_SIZE; ++ bindex++) { ++ h_file = au_hf_dir(file, bindex); ++ if (h_file && file_inode(h_file)) ++ sz += vfsub_f_size_read(h_file); ++ } ++ } else { ++ AuDebugOn(!dentry); ++ AuDebugOn(!d_is_dir(dentry)); ++ ++ bbot = au_dbtaildir(dentry); ++ for (bindex = au_dbtop(dentry); ++ bindex <= bbot && sz < KMALLOC_MAX_SIZE; ++ bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && d_is_positive(h_dentry)) ++ sz += i_size_read(d_inode(h_dentry)); ++ } ++ } ++ if (sz < KMALLOC_MAX_SIZE) ++ sz = roundup_pow_of_two(sz); ++ if (sz > KMALLOC_MAX_SIZE) ++ sz = KMALLOC_MAX_SIZE; ++ else if (sz < NAME_MAX) { ++ BUILD_BUG_ON(AUFS_RDBLK_DEF < NAME_MAX); ++ sz = AUFS_RDBLK_DEF; ++ } ++ return sz; ++} ++ ++struct au_dir_ts_arg { ++ struct dentry *dentry; ++ aufs_bindex_t brid; ++}; ++ ++static void au_do_dir_ts(void *arg) ++{ ++ struct au_dir_ts_arg *a = arg; ++ struct au_dtime dt; ++ struct path h_path; ++ struct inode *dir, *h_dir; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_hinode *hdir; ++ int err; ++ aufs_bindex_t btop, bindex; ++ ++ sb = a->dentry->d_sb; ++ if (d_really_is_negative(a->dentry)) ++ goto out; ++ /* no dir->i_mutex lock */ ++ aufs_read_lock(a->dentry, AuLock_DW); /* noflush */ ++ ++ dir = d_inode(a->dentry); ++ btop = au_ibtop(dir); ++ bindex = au_br_index(sb, a->brid); ++ if (bindex < btop) ++ goto out_unlock; ++ ++ br = au_sbr(sb, bindex); ++ h_path.dentry = au_h_dptr(a->dentry, bindex); ++ if (!h_path.dentry) ++ goto out_unlock; ++ h_path.mnt = au_br_mnt(br); ++ au_dtime_store(&dt, a->dentry, &h_path); ++ ++ br = au_sbr(sb, btop); ++ if (!au_br_writable(br->br_perm)) ++ goto out_unlock; ++ h_path.dentry = au_h_dptr(a->dentry, btop); ++ h_path.mnt = au_br_mnt(br); ++ err = vfsub_mnt_want_write(h_path.mnt); ++ if (err) ++ goto out_unlock; ++ hdir = au_hi(dir, btop); ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ h_dir = au_h_iptr(dir, btop); ++ if (h_dir->i_nlink ++ && timespec64_compare(&h_dir->i_mtime, &dt.dt_mtime) < 0) { ++ dt.dt_h_path = h_path; ++ au_dtime_revert(&dt); ++ } ++ au_hn_inode_unlock(hdir); ++ vfsub_mnt_drop_write(h_path.mnt); ++ au_cpup_attr_timesizes(dir); ++ ++out_unlock: ++ aufs_read_unlock(a->dentry, AuLock_DW); ++out: ++ dput(a->dentry); ++ au_nwt_done(&au_sbi(sb)->si_nowait); ++ au_kfree_try_rcu(arg); ++} ++ ++void au_dir_ts(struct inode *dir, aufs_bindex_t bindex) ++{ ++ int perm, wkq_err; ++ aufs_bindex_t btop; ++ struct au_dir_ts_arg *arg; ++ struct dentry *dentry; ++ struct super_block *sb; ++ ++ IMustLock(dir); ++ ++ dentry = d_find_any_alias(dir); ++ AuDebugOn(!dentry); ++ sb = dentry->d_sb; ++ btop = au_ibtop(dir); ++ if (btop == bindex) { ++ au_cpup_attr_timesizes(dir); ++ goto out; ++ } ++ ++ perm = au_sbr_perm(sb, btop); ++ if (!au_br_writable(perm)) ++ goto out; ++ ++ arg = kmalloc(sizeof(*arg), GFP_NOFS); ++ if (!arg) ++ goto out; ++ ++ arg->dentry = dget(dentry); /* will be dput-ted by au_do_dir_ts() */ ++ arg->brid = au_sbr_id(sb, bindex); ++ wkq_err = au_wkq_nowait(au_do_dir_ts, arg, sb, /*flags*/0); ++ if (unlikely(wkq_err)) { ++ pr_err("wkq %d\n", wkq_err); ++ dput(dentry); ++ au_kfree_try_rcu(arg); ++ } ++ ++out: ++ dput(dentry); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int reopen_dir(struct file *file) ++{ ++ int err; ++ unsigned int flags; ++ aufs_bindex_t bindex, btail, btop; ++ struct dentry *dentry, *h_dentry; ++ struct file *h_file; ++ ++ /* open all lower dirs */ ++ dentry = file->f_path.dentry; ++ btop = au_dbtop(dentry); ++ for (bindex = au_fbtop(file); bindex < btop; bindex++) ++ au_set_h_fptr(file, bindex, NULL); ++ au_set_fbtop(file, btop); ++ ++ btail = au_dbtaildir(dentry); ++ for (bindex = au_fbbot_dir(file); btail < bindex; bindex--) ++ au_set_h_fptr(file, bindex, NULL); ++ au_set_fbbot_dir(file, btail); ++ ++ flags = vfsub_file_flags(file); ++ for (bindex = btop; bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ h_file = au_hf_dir(file, bindex); ++ if (h_file) ++ continue; ++ ++ h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; /* close all? */ ++ au_set_h_fptr(file, bindex, h_file); ++ } ++ au_update_figen(file); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ err = 0; ++ ++out: ++ return err; ++} ++ ++static int do_open_dir(struct file *file, int flags, struct file *h_file) ++{ ++ int err; ++ aufs_bindex_t bindex, btail; ++ struct dentry *dentry, *h_dentry; ++ struct vfsmount *mnt; ++ ++ FiMustWriteLock(file); ++ AuDebugOn(h_file); ++ ++ err = 0; ++ mnt = file->f_path.mnt; ++ dentry = file->f_path.dentry; ++ file->f_version = inode_query_iversion(d_inode(dentry)); ++ bindex = au_dbtop(dentry); ++ au_set_fbtop(file, bindex); ++ btail = au_dbtaildir(dentry); ++ au_set_fbbot_dir(file, btail); ++ for (; !err && bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ ++ err = vfsub_test_mntns(mnt, h_dentry->d_sb); ++ if (unlikely(err)) ++ break; ++ h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0); ++ if (IS_ERR(h_file)) { ++ err = PTR_ERR(h_file); ++ break; ++ } ++ au_set_h_fptr(file, bindex, h_file); ++ } ++ au_update_figen(file); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ if (!err) ++ return 0; /* success */ ++ ++ /* close all */ ++ for (bindex = au_fbtop(file); bindex <= btail; bindex++) ++ au_set_h_fptr(file, bindex, NULL); ++ au_set_fbtop(file, -1); ++ au_set_fbbot_dir(file, -1); ++ ++ return err; ++} ++ ++static int aufs_open_dir(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ int err; ++ struct super_block *sb; ++ struct au_fidir *fidir; ++ ++ err = -ENOMEM; ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ fidir = au_fidir_alloc(sb); ++ if (fidir) { ++ struct au_do_open_args args = { ++ .open = do_open_dir, ++ .fidir = fidir ++ }; ++ err = au_do_open(file, &args); ++ if (unlikely(err)) ++ au_kfree_rcu(fidir); ++ } ++ si_read_unlock(sb); ++ return err; ++} ++ ++static int aufs_release_dir(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ struct au_vdir *vdir_cache; ++ struct au_finfo *finfo; ++ struct au_fidir *fidir; ++ struct au_hfile *hf; ++ aufs_bindex_t bindex, bbot; ++ ++ finfo = au_fi(file); ++ fidir = finfo->fi_hdir; ++ if (fidir) { ++ au_hbl_del(&finfo->fi_hlist, ++ &au_sbi(file->f_path.dentry->d_sb)->si_files); ++ vdir_cache = fidir->fd_vdir_cache; /* lock-free */ ++ if (vdir_cache) ++ au_vdir_free(vdir_cache); ++ ++ bindex = finfo->fi_btop; ++ if (bindex >= 0) { ++ hf = fidir->fd_hfile + bindex; ++ /* ++ * calls fput() instead of filp_close(), ++ * since no dnotify or lock for the lower file. ++ */ ++ bbot = fidir->fd_bbot; ++ for (; bindex <= bbot; bindex++, hf++) ++ if (hf->hf_file) ++ au_hfput(hf, /*execed*/0); ++ } ++ au_kfree_rcu(fidir); ++ finfo->fi_hdir = NULL; ++ } ++ au_finfo_fin(file); ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_flush_dir(struct file *file, fl_owner_t id) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct file *h_file; ++ ++ err = 0; ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); !err && bindex <= bbot; bindex++) { ++ h_file = au_hf_dir(file, bindex); ++ if (h_file) ++ err = vfsub_flush(h_file, id); ++ } ++ return err; ++} ++ ++static int aufs_flush_dir(struct file *file, fl_owner_t id) ++{ ++ return au_do_flush(file, id, au_do_flush_dir); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_fsync_dir_no_file(struct dentry *dentry, int datasync) ++{ ++ int err; ++ aufs_bindex_t bbot, bindex; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ bbot = au_dbbot(dentry); ++ for (bindex = au_dbtop(dentry); !err && bindex <= bbot; bindex++) { ++ struct path h_path; ++ ++ if (au_test_ro(sb, bindex, inode)) ++ continue; ++ h_path.dentry = au_h_dptr(dentry, bindex); ++ if (!h_path.dentry) ++ continue; ++ ++ h_path.mnt = au_sbr_mnt(sb, bindex); ++ err = vfsub_fsync(NULL, &h_path, datasync); ++ } ++ ++ return err; ++} ++ ++static int au_do_fsync_dir(struct file *file, int datasync) ++{ ++ int err; ++ aufs_bindex_t bbot, bindex; ++ struct file *h_file; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1, /*fi_lsc*/0); ++ if (unlikely(err)) ++ goto out; ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); !err && bindex <= bbot; bindex++) { ++ h_file = au_hf_dir(file, bindex); ++ if (!h_file || au_test_ro(sb, bindex, inode)) ++ continue; ++ ++ err = vfsub_fsync(h_file, &h_file->f_path, datasync); ++ } ++ ++out: ++ return err; ++} ++ ++/* ++ * @file may be NULL ++ */ ++static int aufs_fsync_dir(struct file *file, loff_t start, loff_t end, ++ int datasync) ++{ ++ int err; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ err = 0; ++ dentry = file->f_path.dentry; ++ inode = d_inode(dentry); ++ inode_lock(inode); ++ sb = dentry->d_sb; ++ si_noflush_read_lock(sb); ++ if (file) ++ err = au_do_fsync_dir(file, datasync); ++ else { ++ di_write_lock_child(dentry); ++ err = au_do_fsync_dir_no_file(dentry, datasync); ++ } ++ au_cpup_attr_timesizes(inode); ++ di_write_unlock(dentry); ++ if (file) ++ fi_write_unlock(file); ++ ++ si_read_unlock(sb); ++ inode_unlock(inode); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_iterate_shared(struct file *file, struct dir_context *ctx) ++{ ++ int err; ++ struct dentry *dentry; ++ struct inode *inode, *h_inode; ++ struct super_block *sb; ++ ++ AuDbg("%pD, ctx{%ps, %llu}\n", file, ctx->actor, ctx->pos); ++ ++ dentry = file->f_path.dentry; ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ ++ sb = dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1, /*fi_lsc*/0); ++ if (unlikely(err)) ++ goto out; ++ err = au_alive_dir(dentry); ++ if (!err) ++ err = au_vdir_init(file); ++ di_downgrade_lock(dentry, AuLock_IR); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ h_inode = au_h_iptr(inode, au_ibtop(inode)); ++ if (!au_test_nfsd()) { ++ err = au_vdir_fill_de(file, ctx); ++ fsstack_copy_attr_atime(inode, h_inode); ++ } else { ++ /* ++ * nfsd filldir may call lookup_one_len(), vfs_getattr(), ++ * encode_fh() and others. ++ */ ++ atomic_inc(&h_inode->i_count); ++ di_read_unlock(dentry, AuLock_IR); ++ si_read_unlock(sb); ++ err = au_vdir_fill_de(file, ctx); ++ fsstack_copy_attr_atime(inode, h_inode); ++ fi_write_unlock(file); ++ iput(h_inode); ++ ++ AuTraceErr(err); ++ return err; ++ } ++ ++out_unlock: ++ di_read_unlock(dentry, AuLock_IR); ++ fi_write_unlock(file); ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define AuTestEmpty_WHONLY 1 ++#define AuTestEmpty_CALLED (1 << 1) ++#define AuTestEmpty_SHWH (1 << 2) ++#define au_ftest_testempty(flags, name) ((flags) & AuTestEmpty_##name) ++#define au_fset_testempty(flags, name) \ ++ do { (flags) |= AuTestEmpty_##name; } while (0) ++#define au_fclr_testempty(flags, name) \ ++ do { (flags) &= ~AuTestEmpty_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_SHWH ++#undef AuTestEmpty_SHWH ++#define AuTestEmpty_SHWH 0 ++#endif ++ ++struct test_empty_arg { ++ struct dir_context ctx; ++ struct au_nhash *whlist; ++ unsigned int flags; ++ int err; ++ aufs_bindex_t bindex; ++}; ++ ++static int test_empty_cb(struct dir_context *ctx, const char *__name, ++ int namelen, loff_t offset __maybe_unused, u64 ino, ++ unsigned int d_type) ++{ ++ struct test_empty_arg *arg = container_of(ctx, struct test_empty_arg, ++ ctx); ++ char *name = (void *)__name; ++ ++ arg->err = 0; ++ au_fset_testempty(arg->flags, CALLED); ++ /* smp_mb(); */ ++ if (name[0] == '.' ++ && (namelen == 1 || (name[1] == '.' && namelen == 2))) ++ goto out; /* success */ ++ ++ if (namelen <= AUFS_WH_PFX_LEN ++ || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { ++ if (au_ftest_testempty(arg->flags, WHONLY) ++ && !au_nhash_test_known_wh(arg->whlist, name, namelen)) ++ arg->err = -ENOTEMPTY; ++ goto out; ++ } ++ ++ name += AUFS_WH_PFX_LEN; ++ namelen -= AUFS_WH_PFX_LEN; ++ if (!au_nhash_test_known_wh(arg->whlist, name, namelen)) ++ arg->err = au_nhash_append_wh ++ (arg->whlist, name, namelen, ino, d_type, arg->bindex, ++ au_ftest_testempty(arg->flags, SHWH)); ++ ++out: ++ /* smp_mb(); */ ++ AuTraceErr(arg->err); ++ return arg->err; ++} ++ ++static int do_test_empty(struct dentry *dentry, struct test_empty_arg *arg) ++{ ++ int err; ++ struct file *h_file; ++ struct au_branch *br; ++ ++ h_file = au_h_open(dentry, arg->bindex, ++ O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_LARGEFILE, ++ /*file*/NULL, /*force_wr*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = 0; ++ if (!au_opt_test(au_mntflags(dentry->d_sb), UDBA_NONE) ++ && !file_inode(h_file)->i_nlink) ++ goto out_put; ++ ++ do { ++ arg->err = 0; ++ au_fclr_testempty(arg->flags, CALLED); ++ /* smp_mb(); */ ++ err = vfsub_iterate_dir(h_file, &arg->ctx); ++ if (err >= 0) ++ err = arg->err; ++ } while (!err && au_ftest_testempty(arg->flags, CALLED)); ++ ++out_put: ++ fput(h_file); ++ br = au_sbr(dentry->d_sb, arg->bindex); ++ au_lcnt_dec(&br->br_nfiles); ++out: ++ return err; ++} ++ ++struct do_test_empty_args { ++ int *errp; ++ struct dentry *dentry; ++ struct test_empty_arg *arg; ++}; ++ ++static void call_do_test_empty(void *args) ++{ ++ struct do_test_empty_args *a = args; ++ *a->errp = do_test_empty(a->dentry, a->arg); ++} ++ ++static int sio_test_empty(struct dentry *dentry, struct test_empty_arg *arg) ++{ ++ int err, wkq_err; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct user_namespace *h_userns; ++ ++ h_userns = au_sbr_userns(dentry->d_sb, arg->bindex); ++ h_dentry = au_h_dptr(dentry, arg->bindex); ++ h_inode = d_inode(h_dentry); ++ /* todo: i_mode changes anytime? */ ++ inode_lock_shared_nested(h_inode, AuLsc_I_CHILD); ++ err = au_test_h_perm_sio(h_userns, h_inode, MAY_EXEC | MAY_READ); ++ inode_unlock_shared(h_inode); ++ if (!err) ++ err = do_test_empty(dentry, arg); ++ else { ++ struct do_test_empty_args args = { ++ .errp = &err, ++ .dentry = dentry, ++ .arg = arg ++ }; ++ unsigned int flags = arg->flags; ++ ++ wkq_err = au_wkq_wait(call_do_test_empty, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ arg->flags = flags; ++ } ++ ++ return err; ++} ++ ++int au_test_empty_lower(struct dentry *dentry) ++{ ++ int err; ++ unsigned int rdhash; ++ aufs_bindex_t bindex, btop, btail; ++ struct au_nhash whlist; ++ struct test_empty_arg arg = { ++ .ctx = { ++ .actor = test_empty_cb ++ } ++ }; ++ int (*test_empty)(struct dentry *dentry, struct test_empty_arg *arg); ++ ++ SiMustAnyLock(dentry->d_sb); ++ ++ rdhash = au_sbi(dentry->d_sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, dentry)); ++ err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ ++ arg.flags = 0; ++ arg.whlist = &whlist; ++ btop = au_dbtop(dentry); ++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)) ++ au_fset_testempty(arg.flags, SHWH); ++ test_empty = do_test_empty; ++ if (au_opt_test(au_mntflags(dentry->d_sb), DIRPERM1)) ++ test_empty = sio_test_empty; ++ arg.bindex = btop; ++ err = test_empty(dentry, &arg); ++ if (unlikely(err)) ++ goto out_whlist; ++ ++ au_fset_testempty(arg.flags, WHONLY); ++ btail = au_dbtaildir(dentry); ++ for (bindex = btop + 1; !err && bindex <= btail; bindex++) { ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && d_is_positive(h_dentry)) { ++ arg.bindex = bindex; ++ err = test_empty(dentry, &arg); ++ } ++ } ++ ++out_whlist: ++ au_nhash_wh_free(&whlist); ++out: ++ return err; ++} ++ ++int au_test_empty(struct dentry *dentry, struct au_nhash *whlist) ++{ ++ int err; ++ struct test_empty_arg arg = { ++ .ctx = { ++ .actor = test_empty_cb ++ } ++ }; ++ aufs_bindex_t bindex, btail; ++ ++ err = 0; ++ arg.whlist = whlist; ++ arg.flags = AuTestEmpty_WHONLY; ++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)) ++ au_fset_testempty(arg.flags, SHWH); ++ btail = au_dbtaildir(dentry); ++ for (bindex = au_dbtop(dentry); !err && bindex <= btail; bindex++) { ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && d_is_positive(h_dentry)) { ++ arg.bindex = bindex; ++ err = sio_test_empty(dentry, &arg); ++ } ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++const struct file_operations aufs_dir_fop = { ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++ .read = generic_read_dir, ++ .iterate_shared = aufs_iterate_shared, ++ .unlocked_ioctl = aufs_ioctl_dir, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = aufs_compat_ioctl_dir, ++#endif ++ .open = aufs_open_dir, ++ .release = aufs_release_dir, ++ .flush = aufs_flush_dir, ++ .fsync = aufs_fsync_dir ++}; +diff -Nurp linux-5.15.37/fs/aufs/dir.h linux-5.15.37-aufs/fs/aufs/dir.h +--- linux-5.15.37/fs/aufs/dir.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/dir.h 2022-04-08 20:22:30.612616475 +0300 +@@ -0,0 +1,121 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * directory operations ++ */ ++ ++#ifndef __AUFS_DIR_H__ ++#define __AUFS_DIR_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* need to be faster and smaller */ ++ ++struct au_nhash { ++ unsigned int nh_num; ++ struct hlist_head *nh_head; ++}; ++ ++struct au_vdir_destr { ++ unsigned char len; ++ unsigned char name[]; ++} __packed; ++ ++struct au_vdir_dehstr { ++ struct hlist_node hash; ++ struct au_vdir_destr *str; ++ struct rcu_head rcu; ++} ____cacheline_aligned_in_smp; ++ ++struct au_vdir_de { ++ ino_t de_ino; ++ unsigned char de_type; ++ /* caution: packed */ ++ struct au_vdir_destr de_str; ++} __packed; ++ ++struct au_vdir_wh { ++ struct hlist_node wh_hash; ++#ifdef CONFIG_AUFS_SHWH ++ ino_t wh_ino; ++ aufs_bindex_t wh_bindex; ++ unsigned char wh_type; ++#else ++ aufs_bindex_t wh_bindex; ++#endif ++ /* caution: packed */ ++ struct au_vdir_destr wh_str; ++} __packed; ++ ++union au_vdir_deblk_p { ++ unsigned char *deblk; ++ struct au_vdir_de *de; ++}; ++ ++struct au_vdir { ++ unsigned char **vd_deblk; ++ unsigned long vd_nblk; ++ struct { ++ unsigned long ul; ++ union au_vdir_deblk_p p; ++ } vd_last; ++ ++ u64 vd_version; ++ unsigned int vd_deblk_sz; ++ unsigned long vd_jiffy; ++ struct rcu_head rcu; ++} ____cacheline_aligned_in_smp; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dir.c */ ++extern const struct file_operations aufs_dir_fop; ++void au_add_nlink(struct inode *dir, struct inode *h_dir); ++void au_sub_nlink(struct inode *dir, struct inode *h_dir); ++loff_t au_dir_size(struct file *file, struct dentry *dentry); ++void au_dir_ts(struct inode *dir, aufs_bindex_t bsrc); ++int au_test_empty_lower(struct dentry *dentry); ++int au_test_empty(struct dentry *dentry, struct au_nhash *whlist); ++ ++/* vdir.c */ ++unsigned int au_rdhash_est(loff_t sz); ++int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp); ++void au_nhash_wh_free(struct au_nhash *whlist); ++int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt, ++ int limit); ++int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen); ++int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino, ++ unsigned int d_type, aufs_bindex_t bindex, ++ unsigned char shwh); ++void au_vdir_free(struct au_vdir *vdir); ++int au_vdir_init(struct file *file); ++int au_vdir_fill_de(struct file *file, struct dir_context *ctx); ++ ++/* ioctl.c */ ++long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg); ++ ++#ifdef CONFIG_AUFS_RDU ++/* rdu.c */ ++long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg); ++#ifdef CONFIG_COMPAT ++long au_rdu_compat_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg); ++#endif ++#else ++AuStub(long, au_rdu_ioctl, return -EINVAL, struct file *file, ++ unsigned int cmd, unsigned long arg) ++#ifdef CONFIG_COMPAT ++AuStub(long, au_rdu_compat_ioctl, return -EINVAL, struct file *file, ++ unsigned int cmd, unsigned long arg) ++#endif ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DIR_H__ */ +diff -Nurp linux-5.15.37/fs/aufs/dirren.c linux-5.15.37-aufs/fs/aufs/dirren.c +--- linux-5.15.37/fs/aufs/dirren.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/dirren.c 2022-04-08 20:22:30.612616475 +0300 +@@ -0,0 +1,1302 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2017-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * special handling in renaming a directory ++ * in order to support looking-up the before-renamed name on the lower readonly ++ * branches ++ */ ++ ++#include ++#include "aufs.h" ++ ++static void au_dr_hino_del(struct au_dr_br *dr, struct au_dr_hino *ent) ++{ ++ int idx; ++ ++ idx = au_dr_ihash(ent->dr_h_ino); ++ au_hbl_del(&ent->dr_hnode, dr->dr_h_ino + idx); ++} ++ ++static int au_dr_hino_test_empty(struct au_dr_br *dr) ++{ ++ int ret, i; ++ struct hlist_bl_head *hbl; ++ ++ ret = 1; ++ for (i = 0; ret && i < AuDirren_NHASH; i++) { ++ hbl = dr->dr_h_ino + i; ++ hlist_bl_lock(hbl); ++ ret &= hlist_bl_empty(hbl); ++ hlist_bl_unlock(hbl); ++ } ++ ++ return ret; ++} ++ ++static struct au_dr_hino *au_dr_hino_find(struct au_dr_br *dr, ino_t ino) ++{ ++ struct au_dr_hino *found, *ent; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ int idx; ++ ++ found = NULL; ++ idx = au_dr_ihash(ino); ++ hbl = dr->dr_h_ino + idx; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(ent, pos, hbl, dr_hnode) ++ if (ent->dr_h_ino == ino) { ++ found = ent; ++ break; ++ } ++ hlist_bl_unlock(hbl); ++ ++ return found; ++} ++ ++int au_dr_hino_test_add(struct au_dr_br *dr, ino_t ino, ++ struct au_dr_hino *add_ent) ++{ ++ int found, idx; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_dr_hino *ent; ++ ++ found = 0; ++ idx = au_dr_ihash(ino); ++ hbl = dr->dr_h_ino + idx; ++#if 0 /* debug print */ ++ { ++ struct hlist_bl_node *tmp; ++ ++ hlist_bl_for_each_entry_safe(ent, pos, tmp, hbl, dr_hnode) ++ AuDbg("hi%llu\n", (unsigned long long)ent->dr_h_ino); ++ } ++#endif ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(ent, pos, hbl, dr_hnode) ++ if (ent->dr_h_ino == ino) { ++ found = 1; ++ break; ++ } ++ if (!found && add_ent) ++ hlist_bl_add_head(&add_ent->dr_hnode, hbl); ++ hlist_bl_unlock(hbl); ++ ++ if (!found && add_ent) ++ AuDbg("i%llu added\n", (unsigned long long)add_ent->dr_h_ino); ++ ++ return found; ++} ++ ++void au_dr_hino_free(struct au_dr_br *dr) ++{ ++ int i; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos, *tmp; ++ struct au_dr_hino *ent; ++ ++ /* SiMustWriteLock(sb); */ ++ ++ for (i = 0; i < AuDirren_NHASH; i++) { ++ hbl = dr->dr_h_ino + i; ++ /* no spinlock since sbinfo must be write-locked */ ++ hlist_bl_for_each_entry_safe(ent, pos, tmp, hbl, dr_hnode) ++ au_kfree_rcu(ent); ++ INIT_HLIST_BL_HEAD(hbl); ++ } ++} ++ ++/* returns the number of inodes or an error */ ++static int au_dr_hino_store(struct super_block *sb, struct au_branch *br, ++ struct file *hinofile) ++{ ++ int err, i; ++ ssize_t ssz; ++ loff_t pos, oldsize; ++ __be64 u64; ++ struct inode *hinoinode; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *n1, *n2; ++ struct au_dr_hino *ent; ++ ++ SiMustWriteLock(sb); ++ AuDebugOn(!au_br_writable(br->br_perm)); ++ ++ hinoinode = file_inode(hinofile); ++ oldsize = i_size_read(hinoinode); ++ ++ err = 0; ++ pos = 0; ++ hbl = br->br_dirren.dr_h_ino; ++ for (i = 0; !err && i < AuDirren_NHASH; i++, hbl++) { ++ /* no bit-lock since sbinfo must be write-locked */ ++ hlist_bl_for_each_entry_safe(ent, n1, n2, hbl, dr_hnode) { ++ AuDbg("hi%llu, %pD2\n", ++ (unsigned long long)ent->dr_h_ino, hinofile); ++ u64 = cpu_to_be64(ent->dr_h_ino); ++ ssz = vfsub_write_k(hinofile, &u64, sizeof(u64), &pos); ++ if (ssz == sizeof(u64)) ++ continue; ++ ++ /* write error */ ++ pr_err("ssz %zd, %pD2\n", ssz, hinofile); ++ err = -ENOSPC; ++ if (ssz < 0) ++ err = ssz; ++ break; ++ } ++ } ++ /* regardless the error */ ++ if (pos < oldsize) { ++ err = vfsub_trunc(&hinofile->f_path, pos, /*attr*/0, hinofile); ++ AuTraceErr(err); ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_dr_hino_load(struct au_dr_br *dr, struct file *hinofile) ++{ ++ int err, hidx; ++ ssize_t ssz; ++ size_t sz, n; ++ loff_t pos; ++ uint64_t u64; ++ struct au_dr_hino *ent; ++ struct inode *hinoinode; ++ struct hlist_bl_head *hbl; ++ ++ err = 0; ++ pos = 0; ++ hbl = dr->dr_h_ino; ++ hinoinode = file_inode(hinofile); ++ sz = i_size_read(hinoinode); ++ AuDebugOn(sz % sizeof(u64)); ++ n = sz / sizeof(u64); ++ while (n--) { ++ ssz = vfsub_read_k(hinofile, &u64, sizeof(u64), &pos); ++ if (unlikely(ssz != sizeof(u64))) { ++ pr_err("ssz %zd, %pD2\n", ssz, hinofile); ++ err = -EINVAL; ++ if (ssz < 0) ++ err = ssz; ++ goto out_free; ++ } ++ ++ ent = kmalloc(sizeof(*ent), GFP_NOFS); ++ if (!ent) { ++ err = -ENOMEM; ++ AuTraceErr(err); ++ goto out_free; ++ } ++ ent->dr_h_ino = be64_to_cpu((__force __be64)u64); ++ AuDbg("hi%llu, %pD2\n", ++ (unsigned long long)ent->dr_h_ino, hinofile); ++ hidx = au_dr_ihash(ent->dr_h_ino); ++ au_hbl_add(&ent->dr_hnode, hbl + hidx); ++ } ++ goto out; /* success */ ++ ++out_free: ++ au_dr_hino_free(dr); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * @bindex/@br is a switch to distinguish whether suspending hnotify or not. ++ * @path is a switch to distinguish load and store. ++ */ ++static int au_dr_hino(struct super_block *sb, aufs_bindex_t bindex, ++ struct au_branch *br, const struct path *path) ++{ ++ int err, flags; ++ unsigned char load, suspend; ++ struct file *hinofile; ++ struct au_hinode *hdir; ++ struct inode *dir, *delegated; ++ struct path hinopath; ++ struct qstr hinoname = QSTR_INIT(AUFS_WH_DR_BRHINO, ++ sizeof(AUFS_WH_DR_BRHINO) - 1); ++ ++ AuDebugOn(bindex < 0 && !br); ++ AuDebugOn(bindex >= 0 && br); ++ ++ err = -EINVAL; ++ suspend = !br; ++ if (suspend) ++ br = au_sbr(sb, bindex); ++ load = !!path; ++ if (!load) { ++ path = &br->br_path; ++ AuDebugOn(!au_br_writable(br->br_perm)); ++ if (unlikely(!au_br_writable(br->br_perm))) ++ goto out; ++ } ++ ++ hdir = NULL; ++ if (suspend) { ++ dir = d_inode(sb->s_root); ++ hdir = au_hinode(au_ii(dir), bindex); ++ dir = hdir->hi_inode; ++ au_hn_inode_lock_nested(hdir, AuLsc_I_CHILD); ++ } else { ++ dir = d_inode(path->dentry); ++ inode_lock_nested(dir, AuLsc_I_CHILD); ++ } ++ hinopath.mnt = path->mnt; ++ hinopath.dentry = vfsub_lkup_one(&hinoname, (struct path *)path); ++ err = PTR_ERR(hinopath.dentry); ++ if (IS_ERR(hinopath.dentry)) ++ goto out_unlock; ++ ++ err = 0; ++ flags = O_RDONLY; ++ if (load) { ++ if (d_is_negative(hinopath.dentry)) ++ goto out_dput; /* success */ ++ } else { ++ if (au_dr_hino_test_empty(&br->br_dirren)) { ++ if (d_is_positive(hinopath.dentry)) { ++ delegated = NULL; ++ err = vfsub_unlink(dir, &hinopath, &delegated, ++ /*force*/0); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ pr_err("ignored err %d, %pd2\n", ++ err, hinopath.dentry); ++ if (unlikely(err == -EWOULDBLOCK)) ++ iput(delegated); ++ err = 0; ++ } ++ goto out_dput; ++ } else if (!d_is_positive(hinopath.dentry)) { ++ err = vfsub_create(dir, &hinopath, 0600, ++ /*want_excl*/false); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out_dput; ++ } ++ flags = O_WRONLY; ++ } ++ hinofile = vfsub_dentry_open(&hinopath, flags); ++ if (suspend) ++ au_hn_inode_unlock(hdir); ++ else ++ inode_unlock(dir); ++ dput(hinopath.dentry); ++ AuTraceErrPtr(hinofile); ++ if (IS_ERR(hinofile)) { ++ err = PTR_ERR(hinofile); ++ goto out; ++ } ++ ++ if (load) ++ err = au_dr_hino_load(&br->br_dirren, hinofile); ++ else ++ err = au_dr_hino_store(sb, br, hinofile); ++ fput(hinofile); ++ goto out; ++ ++out_dput: ++ dput(hinopath.dentry); ++out_unlock: ++ if (suspend) ++ au_hn_inode_unlock(hdir); ++ else ++ inode_unlock(dir); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_dr_brid_init(struct au_dr_brid *brid, const struct path *path) ++{ ++ int err; ++ struct kstatfs kstfs; ++ dev_t dev; ++ struct dentry *dentry; ++ struct super_block *sb; ++ ++ err = vfs_statfs((void *)path, &kstfs); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out; ++ ++ /* todo: support for UUID */ ++ ++ if (kstfs.f_fsid.val[0] || kstfs.f_fsid.val[1]) { ++ brid->type = AuBrid_FSID; ++ brid->fsid = kstfs.f_fsid; ++ } else { ++ dentry = path->dentry; ++ sb = dentry->d_sb; ++ dev = sb->s_dev; ++ if (dev) { ++ brid->type = AuBrid_DEV; ++ brid->dev = dev; ++ } ++ } ++ ++out: ++ return err; ++} ++ ++int au_dr_br_init(struct super_block *sb, struct au_branch *br, ++ const struct path *path) ++{ ++ int err, i; ++ struct au_dr_br *dr; ++ struct hlist_bl_head *hbl; ++ ++ dr = &br->br_dirren; ++ hbl = dr->dr_h_ino; ++ for (i = 0; i < AuDirren_NHASH; i++, hbl++) ++ INIT_HLIST_BL_HEAD(hbl); ++ ++ err = au_dr_brid_init(&dr->dr_brid, path); ++ if (unlikely(err)) ++ goto out; ++ ++ if (au_opt_test(au_mntflags(sb), DIRREN)) ++ err = au_dr_hino(sb, /*bindex*/-1, br, path); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_dr_br_fin(struct super_block *sb, struct au_branch *br) ++{ ++ int err; ++ ++ err = 0; ++ if (au_br_writable(br->br_perm)) ++ err = au_dr_hino(sb, /*bindex*/-1, br, /*path*/NULL); ++ if (!err) ++ au_dr_hino_free(&br->br_dirren); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_brid_str(struct au_dr_brid *brid, struct inode *h_inode, ++ char *buf, size_t sz) ++{ ++ int err; ++ unsigned int major, minor; ++ char *p; ++ ++ p = buf; ++ err = snprintf(p, sz, "%d_", brid->type); ++ AuDebugOn(err > sz); ++ p += err; ++ sz -= err; ++ switch (brid->type) { ++ case AuBrid_Unset: ++ return -EINVAL; ++ case AuBrid_UUID: ++ err = snprintf(p, sz, "%pU", brid->uuid.b); ++ break; ++ case AuBrid_FSID: ++ err = snprintf(p, sz, "%08x-%08x", ++ brid->fsid.val[0], brid->fsid.val[1]); ++ break; ++ case AuBrid_DEV: ++ major = MAJOR(brid->dev); ++ minor = MINOR(brid->dev); ++ if (major <= 0xff && minor <= 0xff) ++ err = snprintf(p, sz, "%02x%02x", major, minor); ++ else ++ err = snprintf(p, sz, "%03x:%05x", major, minor); ++ break; ++ } ++ AuDebugOn(err > sz); ++ p += err; ++ sz -= err; ++ err = snprintf(p, sz, "_%llu", (unsigned long long)h_inode->i_ino); ++ AuDebugOn(err > sz); ++ p += err; ++ sz -= err; ++ ++ return p - buf; ++} ++ ++static int au_drinfo_name(struct au_branch *br, char *name, int len) ++{ ++ int rlen; ++ struct dentry *br_dentry; ++ struct inode *br_inode; ++ ++ br_dentry = au_br_dentry(br); ++ br_inode = d_inode(br_dentry); ++ rlen = au_brid_str(&br->br_dirren.dr_brid, br_inode, name, len); ++ AuDebugOn(rlen >= AUFS_DIRREN_ENV_VAL_SZ); ++ AuDebugOn(rlen > len); ++ ++ return rlen; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * from the given @h_dentry, construct drinfo at @*fdata. ++ * when the size of @*fdata is not enough, reallocate and return new @fdata and ++ * @allocated. ++ */ ++static int au_drinfo_construct(struct au_drinfo_fdata **fdata, ++ struct dentry *h_dentry, ++ unsigned char *allocated) ++{ ++ int err, v; ++ struct au_drinfo_fdata *f, *p; ++ struct au_drinfo *drinfo; ++ struct inode *h_inode; ++ struct qstr *qname; ++ ++ err = 0; ++ f = *fdata; ++ h_inode = d_inode(h_dentry); ++ qname = &h_dentry->d_name; ++ drinfo = &f->drinfo; ++ drinfo->ino = (__force uint64_t)cpu_to_be64(h_inode->i_ino); ++ drinfo->oldnamelen = qname->len; ++ if (*allocated < sizeof(*f) + qname->len) { ++ v = roundup_pow_of_two(*allocated + qname->len); ++ p = au_krealloc(f, v, GFP_NOFS, /*may_shrink*/0); ++ if (unlikely(!p)) { ++ err = -ENOMEM; ++ AuTraceErr(err); ++ goto out; ++ } ++ f = p; ++ *fdata = f; ++ *allocated = v; ++ drinfo = &f->drinfo; ++ } ++ memcpy(drinfo->oldname, qname->name, qname->len); ++ AuDbg("i%llu, %.*s\n", ++ be64_to_cpu((__force __be64)drinfo->ino), drinfo->oldnamelen, ++ drinfo->oldname); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* callers have to free the return value */ ++static struct au_drinfo *au_drinfo_read_k(struct file *file, ino_t h_ino) ++{ ++ struct au_drinfo *ret, *drinfo; ++ struct au_drinfo_fdata fdata; ++ int len; ++ loff_t pos; ++ ssize_t ssz; ++ ++ ret = ERR_PTR(-EIO); ++ pos = 0; ++ ssz = vfsub_read_k(file, &fdata, sizeof(fdata), &pos); ++ if (unlikely(ssz != sizeof(fdata))) { ++ AuIOErr("ssz %zd, %u, %pD2\n", ++ ssz, (unsigned int)sizeof(fdata), file); ++ goto out; ++ } ++ ++ fdata.magic = ntohl((__force __be32)fdata.magic); ++ switch (fdata.magic) { ++ case AUFS_DRINFO_MAGIC_V1: ++ break; ++ default: ++ AuIOErr("magic-num 0x%x, 0x%x, %pD2\n", ++ fdata.magic, AUFS_DRINFO_MAGIC_V1, file); ++ goto out; ++ } ++ ++ drinfo = &fdata.drinfo; ++ len = drinfo->oldnamelen; ++ if (!len) { ++ AuIOErr("broken drinfo %pD2\n", file); ++ goto out; ++ } ++ ++ ret = NULL; ++ drinfo->ino = be64_to_cpu((__force __be64)drinfo->ino); ++ if (unlikely(h_ino && drinfo->ino != h_ino)) { ++ AuDbg("ignored i%llu, i%llu, %pD2\n", ++ (unsigned long long)drinfo->ino, ++ (unsigned long long)h_ino, file); ++ goto out; /* success */ ++ } ++ ++ ret = kmalloc(sizeof(*ret) + len, GFP_NOFS); ++ if (unlikely(!ret)) { ++ ret = ERR_PTR(-ENOMEM); ++ AuTraceErrPtr(ret); ++ goto out; ++ } ++ ++ *ret = *drinfo; ++ ssz = vfsub_read_k(file, (void *)ret->oldname, len, &pos); ++ if (unlikely(ssz != len)) { ++ au_kfree_rcu(ret); ++ ret = ERR_PTR(-EIO); ++ AuIOErr("ssz %zd, %u, %pD2\n", ssz, len, file); ++ goto out; ++ } ++ ++ AuDbg("oldname %.*s\n", ret->oldnamelen, ret->oldname); ++ ++out: ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* in order to be revertible */ ++struct au_drinfo_rev_elm { ++ int created; ++ struct dentry *info_dentry; ++ struct au_drinfo *info_last; ++}; ++ ++struct au_drinfo_rev { ++ unsigned char already; ++ aufs_bindex_t nelm; ++ struct au_drinfo_rev_elm elm[]; ++}; ++ ++/* todo: isn't it too large? */ ++struct au_drinfo_store { ++ struct path h_ppath; ++ struct dentry *h_dentry; ++ struct au_drinfo_fdata *fdata; ++ char *infoname; /* inside of whname, just after PFX */ ++ char whname[sizeof(AUFS_WH_DR_INFO_PFX) + AUFS_DIRREN_ENV_VAL_SZ]; ++ aufs_bindex_t btgt, btail; ++ unsigned char no_sio, ++ allocated, /* current size of *fdata */ ++ infonamelen, /* room size for p */ ++ whnamelen, /* length of the generated name */ ++ renameback; /* renamed back */ ++}; ++ ++/* on rename(2) error, the caller should revert it using @elm */ ++static int au_drinfo_do_store(struct au_drinfo_store *w, ++ struct au_drinfo_rev_elm *elm) ++{ ++ int err, len; ++ ssize_t ssz; ++ loff_t pos; ++ struct path infopath = { ++ .mnt = w->h_ppath.mnt ++ }; ++ struct inode *h_dir, *h_inode, *delegated; ++ struct file *infofile; ++ struct qstr *qname; ++ ++ AuDebugOn(elm ++ && memcmp(elm, page_address(ZERO_PAGE(0)), sizeof(*elm))); ++ ++ infopath.dentry = vfsub_lookup_one_len(w->whname, &w->h_ppath, ++ w->whnamelen); ++ AuTraceErrPtr(infopath.dentry); ++ if (IS_ERR(infopath.dentry)) { ++ err = PTR_ERR(infopath.dentry); ++ goto out; ++ } ++ ++ err = 0; ++ h_dir = d_inode(w->h_ppath.dentry); ++ if (elm && d_is_negative(infopath.dentry)) { ++ err = vfsub_create(h_dir, &infopath, 0600, /*want_excl*/true); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out_dput; ++ elm->created = 1; ++ elm->info_dentry = dget(infopath.dentry); ++ } ++ ++ infofile = vfsub_dentry_open(&infopath, O_RDWR); ++ AuTraceErrPtr(infofile); ++ if (IS_ERR(infofile)) { ++ err = PTR_ERR(infofile); ++ goto out_dput; ++ } ++ ++ h_inode = d_inode(infopath.dentry); ++ if (elm && i_size_read(h_inode)) { ++ h_inode = d_inode(w->h_dentry); ++ elm->info_last = au_drinfo_read_k(infofile, h_inode->i_ino); ++ AuTraceErrPtr(elm->info_last); ++ if (IS_ERR(elm->info_last)) { ++ err = PTR_ERR(elm->info_last); ++ elm->info_last = NULL; ++ AuDebugOn(elm->info_dentry); ++ goto out_fput; ++ } ++ } ++ ++ if (elm && w->renameback) { ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, &infopath, &delegated, /*force*/0); ++ AuTraceErr(err); ++ if (unlikely(err == -EWOULDBLOCK)) ++ iput(delegated); ++ goto out_fput; ++ } ++ ++ pos = 0; ++ qname = &w->h_dentry->d_name; ++ len = sizeof(*w->fdata) + qname->len; ++ if (!elm) ++ len = sizeof(*w->fdata) + w->fdata->drinfo.oldnamelen; ++ ssz = vfsub_write_k(infofile, w->fdata, len, &pos); ++ if (ssz == len) { ++ AuDbg("hi%llu, %.*s\n", w->fdata->drinfo.ino, ++ w->fdata->drinfo.oldnamelen, w->fdata->drinfo.oldname); ++ goto out_fput; /* success */ ++ } else { ++ err = -EIO; ++ if (ssz < 0) ++ err = ssz; ++ /* the caller should revert it using @elm */ ++ } ++ ++out_fput: ++ fput(infofile); ++out_dput: ++ dput(infopath.dentry); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++struct au_call_drinfo_do_store_args { ++ int *errp; ++ struct au_drinfo_store *w; ++ struct au_drinfo_rev_elm *elm; ++}; ++ ++static void au_call_drinfo_do_store(void *args) ++{ ++ struct au_call_drinfo_do_store_args *a = args; ++ ++ *a->errp = au_drinfo_do_store(a->w, a->elm); ++} ++ ++static int au_drinfo_store_sio(struct au_drinfo_store *w, ++ struct au_drinfo_rev_elm *elm) ++{ ++ int err, wkq_err; ++ ++ if (w->no_sio) ++ err = au_drinfo_do_store(w, elm); ++ else { ++ struct au_call_drinfo_do_store_args a = { ++ .errp = &err, ++ .w = w, ++ .elm = elm ++ }; ++ wkq_err = au_wkq_wait(au_call_drinfo_do_store, &a); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ AuTraceErr(err); ++ ++ return err; ++} ++ ++static int au_drinfo_store_work_init(struct au_drinfo_store *w, ++ aufs_bindex_t btgt) ++{ ++ int err; ++ ++ memset(w, 0, sizeof(*w)); ++ w->allocated = roundup_pow_of_two(sizeof(*w->fdata) + 40); ++ strcpy(w->whname, AUFS_WH_DR_INFO_PFX); ++ w->infoname = w->whname + sizeof(AUFS_WH_DR_INFO_PFX) - 1; ++ w->infonamelen = sizeof(w->whname) - sizeof(AUFS_WH_DR_INFO_PFX); ++ w->btgt = btgt; ++ w->no_sio = !!uid_eq(current_fsuid(), GLOBAL_ROOT_UID); ++ ++ err = -ENOMEM; ++ w->fdata = kcalloc(1, w->allocated, GFP_NOFS); ++ if (unlikely(!w->fdata)) { ++ AuTraceErr(err); ++ goto out; ++ } ++ w->fdata->magic = (__force uint32_t)htonl(AUFS_DRINFO_MAGIC_V1); ++ err = 0; ++ ++out: ++ return err; ++} ++ ++static void au_drinfo_store_work_fin(struct au_drinfo_store *w) ++{ ++ au_kfree_rcu(w->fdata); ++} ++ ++static void au_drinfo_store_rev(struct au_drinfo_rev *rev, ++ struct au_drinfo_store *w) ++{ ++ struct au_drinfo_rev_elm *elm; ++ struct inode *h_dir, *delegated; ++ int err, nelm; ++ struct path infopath = { ++ .mnt = w->h_ppath.mnt ++ }; ++ ++ h_dir = d_inode(w->h_ppath.dentry); ++ IMustLock(h_dir); ++ ++ err = 0; ++ elm = rev->elm; ++ for (nelm = rev->nelm; nelm > 0; nelm--, elm++) { ++ AuDebugOn(elm->created && elm->info_last); ++ if (elm->created) { ++ AuDbg("here\n"); ++ delegated = NULL; ++ infopath.dentry = elm->info_dentry; ++ err = vfsub_unlink(h_dir, &infopath, &delegated, ++ !w->no_sio); ++ AuTraceErr(err); ++ if (unlikely(err == -EWOULDBLOCK)) ++ iput(delegated); ++ dput(elm->info_dentry); ++ } else if (elm->info_last) { ++ AuDbg("here\n"); ++ w->fdata->drinfo = *elm->info_last; ++ memcpy(w->fdata->drinfo.oldname, ++ elm->info_last->oldname, ++ elm->info_last->oldnamelen); ++ err = au_drinfo_store_sio(w, /*elm*/NULL); ++ au_kfree_rcu(elm->info_last); ++ } ++ if (unlikely(err)) ++ AuIOErr("%d, %s\n", err, w->whname); ++ /* go on even if err */ ++ } ++} ++ ++/* caller has to call au_dr_rename_fin() later */ ++static int au_drinfo_store(struct dentry *dentry, aufs_bindex_t btgt, ++ struct qstr *dst_name, void *_rev) ++{ ++ int err, sz, nelm; ++ aufs_bindex_t bindex, btail; ++ struct au_drinfo_store work; ++ struct au_drinfo_rev *rev, **p; ++ struct au_drinfo_rev_elm *elm; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_hinode *hdir; ++ ++ err = au_drinfo_store_work_init(&work, btgt); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out; ++ ++ err = -ENOMEM; ++ btail = au_dbtaildir(dentry); ++ nelm = btail - btgt; ++ sz = sizeof(*rev) + sizeof(*elm) * nelm; ++ rev = kcalloc(1, sz, GFP_NOFS); ++ if (unlikely(!rev)) { ++ AuTraceErr(err); ++ goto out_args; ++ } ++ rev->nelm = nelm; ++ elm = rev->elm; ++ p = _rev; ++ *p = rev; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ work.h_ppath.dentry = au_h_dptr(dentry, btgt); ++ work.h_ppath.mnt = au_sbr_mnt(sb, btgt); ++ hdir = au_hi(d_inode(dentry), btgt); ++ au_hn_inode_lock_nested(hdir, AuLsc_I_CHILD); ++ for (bindex = btgt + 1; bindex <= btail; bindex++, elm++) { ++ work.h_dentry = au_h_dptr(dentry, bindex); ++ if (!work.h_dentry) ++ continue; ++ ++ err = au_drinfo_construct(&work.fdata, work.h_dentry, ++ &work.allocated); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ break; ++ ++ work.renameback = au_qstreq(&work.h_dentry->d_name, dst_name); ++ br = au_sbr(sb, bindex); ++ work.whnamelen = sizeof(AUFS_WH_DR_INFO_PFX) - 1; ++ work.whnamelen += au_drinfo_name(br, work.infoname, ++ work.infonamelen); ++ AuDbg("whname %.*s, i%llu, %.*s\n", ++ work.whnamelen, work.whname, ++ be64_to_cpu((__force __be64)work.fdata->drinfo.ino), ++ work.fdata->drinfo.oldnamelen, ++ work.fdata->drinfo.oldname); ++ ++ err = au_drinfo_store_sio(&work, elm); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ break; ++ } ++ if (unlikely(err)) { ++ /* revert all drinfo */ ++ au_drinfo_store_rev(rev, &work); ++ au_kfree_try_rcu(rev); ++ *p = NULL; ++ } ++ au_hn_inode_unlock(hdir); ++ ++out_args: ++ au_drinfo_store_work_fin(&work); ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_dr_rename(struct dentry *src, aufs_bindex_t bindex, ++ struct qstr *dst_name, void *_rev) ++{ ++ int err, already; ++ ino_t ino; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_dr_br *dr; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct au_dr_hino *ent; ++ struct au_drinfo_rev *rev, **p; ++ ++ AuDbg("bindex %d\n", bindex); ++ ++ err = -ENOMEM; ++ ent = kmalloc(sizeof(*ent), GFP_NOFS); ++ if (unlikely(!ent)) ++ goto out; ++ ++ sb = src->d_sb; ++ br = au_sbr(sb, bindex); ++ dr = &br->br_dirren; ++ h_dentry = au_h_dptr(src, bindex); ++ h_inode = d_inode(h_dentry); ++ ino = h_inode->i_ino; ++ ent->dr_h_ino = ino; ++ already = au_dr_hino_test_add(dr, ino, ent); ++ AuDbg("b%d, hi%llu, already %d\n", ++ bindex, (unsigned long long)ino, already); ++ ++ err = au_drinfo_store(src, bindex, dst_name, _rev); ++ AuTraceErr(err); ++ if (!err) { ++ p = _rev; ++ rev = *p; ++ rev->already = already; ++ goto out; /* success */ ++ } ++ ++ /* revert */ ++ if (!already) ++ au_dr_hino_del(dr, ent); ++ au_kfree_rcu(ent); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_dr_rename_fin(struct dentry *src, aufs_bindex_t btgt, void *_rev) ++{ ++ struct au_drinfo_rev *rev; ++ struct au_drinfo_rev_elm *elm; ++ int nelm; ++ ++ rev = _rev; ++ elm = rev->elm; ++ for (nelm = rev->nelm; nelm > 0; nelm--, elm++) { ++ dput(elm->info_dentry); ++ au_kfree_rcu(elm->info_last); ++ } ++ au_kfree_try_rcu(rev); ++} ++ ++void au_dr_rename_rev(struct dentry *src, aufs_bindex_t btgt, void *_rev) ++{ ++ int err; ++ struct au_drinfo_store work; ++ struct au_drinfo_rev *rev = _rev; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct inode *h_inode; ++ struct au_dr_br *dr; ++ struct au_dr_hino *ent; ++ ++ err = au_drinfo_store_work_init(&work, btgt); ++ if (unlikely(err)) ++ goto out; ++ ++ sb = src->d_sb; ++ br = au_sbr(sb, btgt); ++ work.h_ppath.dentry = au_h_dptr(src, btgt); ++ work.h_ppath.mnt = au_br_mnt(br); ++ au_drinfo_store_rev(rev, &work); ++ au_drinfo_store_work_fin(&work); ++ if (rev->already) ++ goto out; ++ ++ dr = &br->br_dirren; ++ h_inode = d_inode(work.h_ppath.dentry); ++ ent = au_dr_hino_find(dr, h_inode->i_ino); ++ BUG_ON(!ent); ++ au_dr_hino_del(dr, ent); ++ au_kfree_rcu(ent); ++ ++out: ++ au_kfree_try_rcu(rev); ++ if (unlikely(err)) ++ pr_err("failed to remove dirren info\n"); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct au_drinfo *au_drinfo_do_load(struct path *h_ppath, ++ char *whname, int whnamelen, ++ struct dentry **info_dentry) ++{ ++ struct au_drinfo *drinfo; ++ struct file *f; ++ struct inode *h_dir; ++ struct path infopath; ++ int unlocked; ++ ++ AuDbg("%pd/%.*s\n", h_ppath->dentry, whnamelen, whname); ++ ++ *info_dentry = NULL; ++ drinfo = NULL; ++ unlocked = 0; ++ h_dir = d_inode(h_ppath->dentry); ++ inode_lock_shared_nested(h_dir, AuLsc_I_PARENT); ++ infopath.dentry = vfsub_lookup_one_len(whname, h_ppath, whnamelen); ++ if (IS_ERR(infopath.dentry)) { ++ drinfo = (void *)infopath.dentry; ++ goto out; ++ } ++ ++ if (d_is_negative(infopath.dentry)) ++ goto out_dput; /* success */ ++ ++ infopath.mnt = h_ppath->mnt; ++ f = vfsub_dentry_open(&infopath, O_RDONLY); ++ inode_unlock_shared(h_dir); ++ unlocked = 1; ++ if (IS_ERR(f)) { ++ drinfo = (void *)f; ++ goto out_dput; ++ } ++ ++ drinfo = au_drinfo_read_k(f, /*h_ino*/0); ++ if (IS_ERR_OR_NULL(drinfo)) ++ goto out_fput; ++ ++ AuDbg("oldname %.*s\n", drinfo->oldnamelen, drinfo->oldname); ++ *info_dentry = dget(infopath.dentry); /* keep it alive */ ++ ++out_fput: ++ fput(f); ++out_dput: ++ dput(infopath.dentry); ++out: ++ if (!unlocked) ++ inode_unlock_shared(h_dir); ++ AuTraceErrPtr(drinfo); ++ return drinfo; ++} ++ ++struct au_drinfo_do_load_args { ++ struct au_drinfo **drinfop; ++ struct path *h_ppath; ++ char *whname; ++ int whnamelen; ++ struct dentry **info_dentry; ++}; ++ ++static void au_call_drinfo_do_load(void *args) ++{ ++ struct au_drinfo_do_load_args *a = args; ++ ++ *a->drinfop = au_drinfo_do_load(a->h_ppath, a->whname, a->whnamelen, ++ a->info_dentry); ++} ++ ++struct au_drinfo_load { ++ struct path h_ppath; ++ struct qstr *qname; ++ unsigned char no_sio; ++ ++ aufs_bindex_t ninfo; ++ struct au_drinfo **drinfo; ++}; ++ ++static int au_drinfo_load(struct au_drinfo_load *w, aufs_bindex_t bindex, ++ struct au_branch *br) ++{ ++ int err, wkq_err, whnamelen, e; ++ char whname[sizeof(AUFS_WH_DR_INFO_PFX) + AUFS_DIRREN_ENV_VAL_SZ] ++ = AUFS_WH_DR_INFO_PFX; ++ struct au_drinfo *drinfo; ++ struct qstr oldname; ++ struct inode *h_dir, *delegated; ++ struct dentry *info_dentry; ++ struct path infopath; ++ ++ whnamelen = sizeof(AUFS_WH_DR_INFO_PFX) - 1; ++ whnamelen += au_drinfo_name(br, whname + whnamelen, ++ sizeof(whname) - whnamelen); ++ if (w->no_sio) ++ drinfo = au_drinfo_do_load(&w->h_ppath, whname, whnamelen, ++ &info_dentry); ++ else { ++ struct au_drinfo_do_load_args args = { ++ .drinfop = &drinfo, ++ .h_ppath = &w->h_ppath, ++ .whname = whname, ++ .whnamelen = whnamelen, ++ .info_dentry = &info_dentry ++ }; ++ wkq_err = au_wkq_wait(au_call_drinfo_do_load, &args); ++ if (unlikely(wkq_err)) ++ drinfo = ERR_PTR(wkq_err); ++ } ++ err = PTR_ERR(drinfo); ++ if (IS_ERR_OR_NULL(drinfo)) ++ goto out; ++ ++ err = 0; ++ oldname.len = drinfo->oldnamelen; ++ oldname.name = drinfo->oldname; ++ if (au_qstreq(w->qname, &oldname)) { ++ /* the name is renamed back */ ++ au_kfree_rcu(drinfo); ++ drinfo = NULL; ++ ++ infopath.dentry = info_dentry; ++ infopath.mnt = w->h_ppath.mnt; ++ h_dir = d_inode(w->h_ppath.dentry); ++ delegated = NULL; ++ inode_lock_nested(h_dir, AuLsc_I_PARENT); ++ e = vfsub_unlink(h_dir, &infopath, &delegated, !w->no_sio); ++ inode_unlock(h_dir); ++ if (unlikely(e)) ++ AuIOErr("ignored %d, %pd2\n", e, &infopath.dentry); ++ if (unlikely(e == -EWOULDBLOCK)) ++ iput(delegated); ++ } ++ au_kfree_rcu(w->drinfo[bindex]); ++ w->drinfo[bindex] = drinfo; ++ dput(info_dentry); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_dr_lkup_free(struct au_drinfo **drinfo, int n) ++{ ++ struct au_drinfo **p = drinfo; ++ ++ while (n-- > 0) ++ au_kfree_rcu(*drinfo++); ++ au_kfree_try_rcu(p); ++} ++ ++int au_dr_lkup(struct au_do_lookup_args *lkup, struct dentry *dentry, ++ aufs_bindex_t btgt) ++{ ++ int err, ninfo; ++ struct au_drinfo_load w; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ struct inode *h_dir; ++ struct au_dr_hino *ent; ++ struct super_block *sb; ++ ++ AuDbg("%.*s, name %.*s, whname %.*s, b%d\n", ++ AuLNPair(&dentry->d_name), AuLNPair(&lkup->dirren.dr_name), ++ AuLNPair(&lkup->whname), btgt); ++ ++ sb = dentry->d_sb; ++ bbot = au_sbbot(sb); ++ w.ninfo = bbot + 1; ++ if (!lkup->dirren.drinfo) { ++ lkup->dirren.drinfo = kcalloc(w.ninfo, ++ sizeof(*lkup->dirren.drinfo), ++ GFP_NOFS); ++ if (unlikely(!lkup->dirren.drinfo)) { ++ err = -ENOMEM; ++ goto out; ++ } ++ lkup->dirren.ninfo = w.ninfo; ++ } ++ w.drinfo = lkup->dirren.drinfo; ++ w.no_sio = !!uid_eq(current_fsuid(), GLOBAL_ROOT_UID); ++ w.h_ppath.dentry = au_h_dptr(dentry, btgt); ++ AuDebugOn(!w.h_ppath.dentry); ++ w.h_ppath.mnt = au_sbr_mnt(sb, btgt); ++ w.qname = &dentry->d_name; ++ ++ ninfo = 0; ++ for (bindex = btgt + 1; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ err = au_drinfo_load(&w, bindex, br); ++ if (unlikely(err)) ++ goto out_free; ++ if (w.drinfo[bindex]) ++ ninfo++; ++ } ++ if (!ninfo) { ++ br = au_sbr(sb, btgt); ++ h_dir = d_inode(w.h_ppath.dentry); ++ ent = au_dr_hino_find(&br->br_dirren, h_dir->i_ino); ++ AuDebugOn(!ent); ++ au_dr_hino_del(&br->br_dirren, ent); ++ au_kfree_rcu(ent); ++ } ++ goto out; /* success */ ++ ++out_free: ++ au_dr_lkup_free(lkup->dirren.drinfo, lkup->dirren.ninfo); ++ lkup->dirren.ninfo = 0; ++ lkup->dirren.drinfo = NULL; ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_dr_lkup_fin(struct au_do_lookup_args *lkup) ++{ ++ au_dr_lkup_free(lkup->dirren.drinfo, lkup->dirren.ninfo); ++} ++ ++int au_dr_lkup_name(struct au_do_lookup_args *lkup, aufs_bindex_t btgt) ++{ ++ int err; ++ struct au_drinfo *drinfo; ++ ++ err = 0; ++ if (!lkup->dirren.drinfo) ++ goto out; ++ AuDebugOn(lkup->dirren.ninfo <= btgt); ++ drinfo = lkup->dirren.drinfo[btgt]; ++ if (!drinfo) ++ goto out; ++ ++ au_kfree_try_rcu(lkup->whname.name); ++ lkup->whname.name = NULL; ++ lkup->dirren.dr_name.len = drinfo->oldnamelen; ++ lkup->dirren.dr_name.name = drinfo->oldname; ++ lkup->name = &lkup->dirren.dr_name; ++ err = au_wh_name_alloc(&lkup->whname, lkup->name); ++ if (!err) ++ AuDbg("name %.*s, whname %.*s, b%d\n", ++ AuLNPair(lkup->name), AuLNPair(&lkup->whname), ++ btgt); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_dr_lkup_h_ino(struct au_do_lookup_args *lkup, aufs_bindex_t bindex, ++ ino_t h_ino) ++{ ++ int match; ++ struct au_drinfo *drinfo; ++ ++ match = 1; ++ if (!lkup->dirren.drinfo) ++ goto out; ++ AuDebugOn(lkup->dirren.ninfo <= bindex); ++ drinfo = lkup->dirren.drinfo[bindex]; ++ if (!drinfo) ++ goto out; ++ ++ match = (drinfo->ino == h_ino); ++ AuDbg("match %d\n", match); ++ ++out: ++ return match; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_dr_opt_set(struct super_block *sb) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ err = 0; ++ bbot = au_sbbot(sb); ++ for (bindex = 0; !err && bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ err = au_dr_hino(sb, bindex, /*br*/NULL, &br->br_path); ++ } ++ ++ return err; ++} ++ ++int au_dr_opt_flush(struct super_block *sb) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ err = 0; ++ bbot = au_sbbot(sb); ++ for (bindex = 0; !err && bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_writable(br->br_perm)) ++ err = au_dr_hino(sb, bindex, /*br*/NULL, /*path*/NULL); ++ } ++ ++ return err; ++} ++ ++int au_dr_opt_clr(struct super_block *sb, int no_flush) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ err = 0; ++ if (!no_flush) { ++ err = au_dr_opt_flush(sb); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ au_dr_hino_free(&br->br_dirren); ++ } ++ ++out: ++ return err; ++} +diff -Nurp linux-5.15.37/fs/aufs/dirren.h linux-5.15.37-aufs/fs/aufs/dirren.h +--- linux-5.15.37/fs/aufs/dirren.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/dirren.h 2022-04-08 20:22:30.612616475 +0300 +@@ -0,0 +1,127 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2017-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * renamed dir info ++ */ ++ ++#ifndef __AUFS_DIRREN_H__ ++#define __AUFS_DIRREN_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include "hbl.h" ++ ++#define AuDirren_NHASH 100 ++ ++#ifdef CONFIG_AUFS_DIRREN ++enum au_brid_type { ++ AuBrid_Unset, ++ AuBrid_UUID, ++ AuBrid_FSID, ++ AuBrid_DEV ++}; ++ ++struct au_dr_brid { ++ enum au_brid_type type; ++ union { ++ uuid_t uuid; /* unimplemented yet */ ++ fsid_t fsid; ++ dev_t dev; ++ }; ++}; ++ ++/* 20 is the max digits length of ulong 64 */ ++/* brid-type "_" uuid "_" inum */ ++#define AUFS_DIRREN_FNAME_SZ (1 + 1 + UUID_STRING_LEN + 20) ++#define AUFS_DIRREN_ENV_VAL_SZ (AUFS_DIRREN_FNAME_SZ + 1 + 20) ++ ++struct au_dr_hino { ++ struct hlist_bl_node dr_hnode; ++ ino_t dr_h_ino; ++}; ++ ++struct au_dr_br { ++ struct hlist_bl_head dr_h_ino[AuDirren_NHASH]; ++ struct au_dr_brid dr_brid; ++}; ++ ++struct au_dr_lookup { ++ /* dr_name is pointed by struct au_do_lookup_args.name */ ++ struct qstr dr_name; /* subset of dr_info */ ++ aufs_bindex_t ninfo; ++ struct au_drinfo **drinfo; ++}; ++#else ++struct au_dr_hino; ++/* empty */ ++struct au_dr_br { }; ++struct au_dr_lookup { }; ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_branch; ++struct au_do_lookup_args; ++struct au_hinode; ++#ifdef CONFIG_AUFS_DIRREN ++int au_dr_hino_test_add(struct au_dr_br *dr, ino_t h_ino, ++ struct au_dr_hino *add_ent); ++void au_dr_hino_free(struct au_dr_br *dr); ++int au_dr_br_init(struct super_block *sb, struct au_branch *br, ++ const struct path *path); ++int au_dr_br_fin(struct super_block *sb, struct au_branch *br); ++int au_dr_rename(struct dentry *src, aufs_bindex_t bindex, ++ struct qstr *dst_name, void *_rev); ++void au_dr_rename_fin(struct dentry *src, aufs_bindex_t btgt, void *rev); ++void au_dr_rename_rev(struct dentry *src, aufs_bindex_t bindex, void *rev); ++int au_dr_lkup(struct au_do_lookup_args *lkup, struct dentry *dentry, ++ aufs_bindex_t bindex); ++int au_dr_lkup_name(struct au_do_lookup_args *lkup, aufs_bindex_t btgt); ++int au_dr_lkup_h_ino(struct au_do_lookup_args *lkup, aufs_bindex_t bindex, ++ ino_t h_ino); ++void au_dr_lkup_fin(struct au_do_lookup_args *lkup); ++int au_dr_opt_set(struct super_block *sb); ++int au_dr_opt_flush(struct super_block *sb); ++int au_dr_opt_clr(struct super_block *sb, int no_flush); ++#else ++AuStubInt0(au_dr_hino_test_add, struct au_dr_br *dr, ino_t h_ino, ++ struct au_dr_hino *add_ent); ++AuStubVoid(au_dr_hino_free, struct au_dr_br *dr); ++AuStubInt0(au_dr_br_init, struct super_block *sb, struct au_branch *br, ++ const struct path *path); ++AuStubInt0(au_dr_br_fin, struct super_block *sb, struct au_branch *br); ++AuStubInt0(au_dr_rename, struct dentry *src, aufs_bindex_t bindex, ++ struct qstr *dst_name, void *_rev); ++AuStubVoid(au_dr_rename_fin, struct dentry *src, aufs_bindex_t btgt, void *rev); ++AuStubVoid(au_dr_rename_rev, struct dentry *src, aufs_bindex_t bindex, ++ void *rev); ++AuStubInt0(au_dr_lkup, struct au_do_lookup_args *lkup, struct dentry *dentry, ++ aufs_bindex_t bindex); ++AuStubInt0(au_dr_lkup_name, struct au_do_lookup_args *lkup, aufs_bindex_t btgt); ++AuStubInt0(au_dr_lkup_h_ino, struct au_do_lookup_args *lkup, ++ aufs_bindex_t bindex, ino_t h_ino); ++AuStubVoid(au_dr_lkup_fin, struct au_do_lookup_args *lkup); ++AuStubInt0(au_dr_opt_set, struct super_block *sb); ++AuStubInt0(au_dr_opt_flush, struct super_block *sb); ++AuStubInt0(au_dr_opt_clr, struct super_block *sb, int no_flush); ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_DIRREN ++static inline int au_dr_ihash(ino_t h_ino) ++{ ++ return h_ino % AuDirren_NHASH; ++} ++#else ++AuStubInt0(au_dr_ihash, ino_t h_ino); ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DIRREN_H__ */ +diff -Nurp linux-5.15.37/fs/aufs/dynop.c linux-5.15.37-aufs/fs/aufs/dynop.c +--- linux-5.15.37/fs/aufs/dynop.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/dynop.c 2022-04-08 20:22:30.612616475 +0300 +@@ -0,0 +1,355 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2010-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * dynamically customizable operations for regular files ++ */ ++ ++#include "aufs.h" ++ ++#define DyPrSym(key) AuDbgSym(key->dk_op.dy_hop) ++ ++/* ++ * How large will these lists be? ++ * Usually just a few elements, 20-30 at most for each, I guess. ++ */ ++static struct hlist_bl_head dynop[AuDyLast]; ++ ++static struct au_dykey *dy_gfind_get(struct hlist_bl_head *hbl, ++ const void *h_op) ++{ ++ struct au_dykey *key, *tmp; ++ struct hlist_bl_node *pos; ++ ++ key = NULL; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(tmp, pos, hbl, dk_hnode) ++ if (tmp->dk_op.dy_hop == h_op) { ++ if (kref_get_unless_zero(&tmp->dk_kref)) ++ key = tmp; ++ break; ++ } ++ hlist_bl_unlock(hbl); ++ ++ return key; ++} ++ ++static struct au_dykey *dy_bradd(struct au_branch *br, struct au_dykey *key) ++{ ++ struct au_dykey **k, *found; ++ const void *h_op = key->dk_op.dy_hop; ++ int i; ++ ++ found = NULL; ++ k = br->br_dykey; ++ for (i = 0; i < AuBrDynOp; i++) ++ if (k[i]) { ++ if (k[i]->dk_op.dy_hop == h_op) { ++ found = k[i]; ++ break; ++ } ++ } else ++ break; ++ if (!found) { ++ spin_lock(&br->br_dykey_lock); ++ for (; i < AuBrDynOp; i++) ++ if (k[i]) { ++ if (k[i]->dk_op.dy_hop == h_op) { ++ found = k[i]; ++ break; ++ } ++ } else { ++ k[i] = key; ++ break; ++ } ++ spin_unlock(&br->br_dykey_lock); ++ BUG_ON(i == AuBrDynOp); /* expand the array */ ++ } ++ ++ return found; ++} ++ ++/* kref_get() if @key is already added */ ++static struct au_dykey *dy_gadd(struct hlist_bl_head *hbl, struct au_dykey *key) ++{ ++ struct au_dykey *tmp, *found; ++ struct hlist_bl_node *pos; ++ const void *h_op = key->dk_op.dy_hop; ++ ++ found = NULL; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(tmp, pos, hbl, dk_hnode) ++ if (tmp->dk_op.dy_hop == h_op) { ++ if (kref_get_unless_zero(&tmp->dk_kref)) ++ found = tmp; ++ break; ++ } ++ if (!found) ++ hlist_bl_add_head(&key->dk_hnode, hbl); ++ hlist_bl_unlock(hbl); ++ ++ if (!found) ++ DyPrSym(key); ++ return found; ++} ++ ++static void dy_free_rcu(struct rcu_head *rcu) ++{ ++ struct au_dykey *key; ++ ++ key = container_of(rcu, struct au_dykey, dk_rcu); ++ DyPrSym(key); ++ kfree(key); ++} ++ ++static void dy_free(struct kref *kref) ++{ ++ struct au_dykey *key; ++ struct hlist_bl_head *hbl; ++ ++ key = container_of(kref, struct au_dykey, dk_kref); ++ hbl = dynop + key->dk_op.dy_type; ++ au_hbl_del(&key->dk_hnode, hbl); ++ call_rcu(&key->dk_rcu, dy_free_rcu); ++} ++ ++void au_dy_put(struct au_dykey *key) ++{ ++ kref_put(&key->dk_kref, dy_free); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define DyDbgSize(cnt, op) AuDebugOn(cnt != sizeof(op)/sizeof(void *)) ++ ++#ifdef CONFIG_AUFS_DEBUG ++#define DyDbgDeclare(cnt) unsigned int cnt = 0 ++#define DyDbgInc(cnt) do { cnt++; } while (0) ++#else ++#define DyDbgDeclare(cnt) do {} while (0) ++#define DyDbgInc(cnt) do {} while (0) ++#endif ++ ++#define DySet(func, dst, src, h_op, h_sb) do { \ ++ DyDbgInc(cnt); \ ++ if (h_op->func) { \ ++ if (src.func) \ ++ dst.func = src.func; \ ++ else \ ++ AuDbg("%s %s\n", au_sbtype(h_sb), #func); \ ++ } \ ++} while (0) ++ ++#define DySetForce(func, dst, src) do { \ ++ AuDebugOn(!src.func); \ ++ DyDbgInc(cnt); \ ++ dst.func = src.func; \ ++} while (0) ++ ++#define DySetAop(func) \ ++ DySet(func, dyaop->da_op, aufs_aop, h_aop, h_sb) ++#define DySetAopForce(func) \ ++ DySetForce(func, dyaop->da_op, aufs_aop) ++ ++static void dy_aop(struct au_dykey *key, const void *h_op, ++ struct super_block *h_sb __maybe_unused) ++{ ++ struct au_dyaop *dyaop = (void *)key; ++ const struct address_space_operations *h_aop = h_op; ++ DyDbgDeclare(cnt); ++ ++ AuDbg("%s\n", au_sbtype(h_sb)); ++ ++ DySetAop(writepage); ++ DySetAopForce(readpage); /* force */ ++ DySetAop(writepages); ++ DySetAop(set_page_dirty); ++ DySetAop(readpages); ++ DySetAop(readahead); ++ DySetAop(write_begin); ++ DySetAop(write_end); ++ DySetAop(bmap); ++ DySetAop(invalidatepage); ++ DySetAop(releasepage); ++ DySetAop(freepage); ++ /* this one will be changed according to an aufs mount option */ ++ DySetAop(direct_IO); ++ DySetAop(migratepage); ++ DySetAop(isolate_page); ++ DySetAop(putback_page); ++ DySetAop(launder_page); ++ DySetAop(is_partially_uptodate); ++ DySetAop(is_dirty_writeback); ++ DySetAop(error_remove_page); ++ DySetAop(swap_activate); ++ DySetAop(swap_deactivate); ++ ++ DyDbgSize(cnt, *h_aop); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void dy_bug(struct kref *kref) ++{ ++ BUG(); ++} ++ ++static struct au_dykey *dy_get(struct au_dynop *op, struct au_branch *br) ++{ ++ struct au_dykey *key, *old; ++ struct hlist_bl_head *hbl; ++ struct op { ++ unsigned int sz; ++ void (*set)(struct au_dykey *key, const void *h_op, ++ struct super_block *h_sb __maybe_unused); ++ }; ++ static const struct op a[] = { ++ [AuDy_AOP] = { ++ .sz = sizeof(struct au_dyaop), ++ .set = dy_aop ++ } ++ }; ++ const struct op *p; ++ ++ hbl = dynop + op->dy_type; ++ key = dy_gfind_get(hbl, op->dy_hop); ++ if (key) ++ goto out_add; /* success */ ++ ++ p = a + op->dy_type; ++ key = kzalloc(p->sz, GFP_NOFS); ++ if (unlikely(!key)) { ++ key = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ ++ key->dk_op.dy_hop = op->dy_hop; ++ kref_init(&key->dk_kref); ++ p->set(key, op->dy_hop, au_br_sb(br)); ++ old = dy_gadd(hbl, key); ++ if (old) { ++ au_kfree_rcu(key); ++ key = old; ++ } ++ ++out_add: ++ old = dy_bradd(br, key); ++ if (old) ++ /* its ref-count should never be zero here */ ++ kref_put(&key->dk_kref, dy_bug); ++out: ++ return key; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * Aufs prohibits O_DIRECT by default even if the branch supports it. ++ * This behaviour is necessary to return an error from open(O_DIRECT) instead ++ * of the succeeding I/O. The dio mount option enables O_DIRECT and makes ++ * open(O_DIRECT) always succeed, but the succeeding I/O may return an error. ++ * See the aufs manual in detail. ++ */ ++static void dy_adx(struct au_dyaop *dyaop, int do_dx) ++{ ++ if (!do_dx) ++ dyaop->da_op.direct_IO = NULL; ++ else ++ dyaop->da_op.direct_IO = aufs_aop.direct_IO; ++} ++ ++static struct au_dyaop *dy_aget(struct au_branch *br, ++ const struct address_space_operations *h_aop, ++ int do_dx) ++{ ++ struct au_dyaop *dyaop; ++ struct au_dynop op; ++ ++ op.dy_type = AuDy_AOP; ++ op.dy_haop = h_aop; ++ dyaop = (void *)dy_get(&op, br); ++ if (IS_ERR(dyaop)) ++ goto out; ++ dy_adx(dyaop, do_dx); ++ ++out: ++ return dyaop; ++} ++ ++int au_dy_iaop(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode) ++{ ++ int err, do_dx; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_dyaop *dyaop; ++ ++ AuDebugOn(!S_ISREG(h_inode->i_mode)); ++ IiMustWriteLock(inode); ++ ++ sb = inode->i_sb; ++ br = au_sbr(sb, bindex); ++ do_dx = !!au_opt_test(au_mntflags(sb), DIO); ++ dyaop = dy_aget(br, h_inode->i_mapping->a_ops, do_dx); ++ err = PTR_ERR(dyaop); ++ if (IS_ERR(dyaop)) ++ /* unnecessary to call dy_fput() */ ++ goto out; ++ ++ err = 0; ++ inode->i_mapping->a_ops = &dyaop->da_op; ++ ++out: ++ return err; ++} ++ ++/* ++ * Is it safe to replace a_ops during the inode/file is in operation? ++ * Yes, I hope so. ++ */ ++int au_dy_irefresh(struct inode *inode) ++{ ++ int err; ++ aufs_bindex_t btop; ++ struct inode *h_inode; ++ ++ err = 0; ++ if (S_ISREG(inode->i_mode)) { ++ btop = au_ibtop(inode); ++ h_inode = au_h_iptr(inode, btop); ++ err = au_dy_iaop(inode, btop, h_inode); ++ } ++ return err; ++} ++ ++void au_dy_arefresh(int do_dx) ++{ ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_dykey *key; ++ ++ hbl = dynop + AuDy_AOP; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(key, pos, hbl, dk_hnode) ++ dy_adx((void *)key, do_dx); ++ hlist_bl_unlock(hbl); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void __init au_dy_init(void) ++{ ++ int i; ++ ++ for (i = 0; i < AuDyLast; i++) ++ INIT_HLIST_BL_HEAD(dynop + i); ++} ++ ++void au_dy_fin(void) ++{ ++ int i; ++ ++ for (i = 0; i < AuDyLast; i++) ++ WARN_ON(!hlist_bl_empty(dynop + i)); ++} +diff -Nurp linux-5.15.37/fs/aufs/dynop.h linux-5.15.37-aufs/fs/aufs/dynop.h +--- linux-5.15.37/fs/aufs/dynop.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/dynop.h 2022-04-08 20:22:30.612616475 +0300 +@@ -0,0 +1,64 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2010-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * dynamically customizable operations (for regular files only) ++ */ ++ ++#ifndef __AUFS_DYNOP_H__ ++#define __AUFS_DYNOP_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++ ++enum {AuDy_AOP, AuDyLast}; ++ ++struct au_dynop { ++ int dy_type; ++ union { ++ const void *dy_hop; ++ const struct address_space_operations *dy_haop; ++ }; ++}; ++ ++struct au_dykey { ++ union { ++ struct hlist_bl_node dk_hnode; ++ struct rcu_head dk_rcu; ++ }; ++ struct au_dynop dk_op; ++ ++ /* ++ * during I am in the branch local array, kref is gotten. when the ++ * branch is removed, kref is put. ++ */ ++ struct kref dk_kref; ++}; ++ ++/* stop unioning since their sizes are very different from each other */ ++struct au_dyaop { ++ struct au_dykey da_key; ++ struct address_space_operations da_op; /* not const */ ++}; ++/* make sure that 'struct au_dykey *' can be any type */ ++static_assert(!offsetof(struct au_dyaop, da_key)); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dynop.c */ ++struct au_branch; ++void au_dy_put(struct au_dykey *key); ++int au_dy_iaop(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode); ++int au_dy_irefresh(struct inode *inode); ++void au_dy_arefresh(int do_dio); ++ ++void __init au_dy_init(void); ++void au_dy_fin(void); ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DYNOP_H__ */ +diff -Nurp linux-5.15.37/fs/aufs/export.c linux-5.15.37-aufs/fs/aufs/export.c +--- linux-5.15.37/fs/aufs/export.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/export.c 2022-04-08 20:22:30.612616475 +0300 +@@ -0,0 +1,817 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * export via nfs ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++union conv { ++#ifdef CONFIG_AUFS_INO_T_64 ++ __u32 a[2]; ++#else ++ __u32 a[1]; ++#endif ++ ino_t ino; ++}; ++ ++static ino_t decode_ino(__u32 *a) ++{ ++ union conv u; ++ ++ BUILD_BUG_ON(sizeof(u.ino) != sizeof(u.a)); ++ u.a[0] = a[0]; ++#ifdef CONFIG_AUFS_INO_T_64 ++ u.a[1] = a[1]; ++#endif ++ return u.ino; ++} ++ ++static void encode_ino(__u32 *a, ino_t ino) ++{ ++ union conv u; ++ ++ u.ino = ino; ++ a[0] = u.a[0]; ++#ifdef CONFIG_AUFS_INO_T_64 ++ a[1] = u.a[1]; ++#endif ++} ++ ++/* NFS file handle */ ++enum { ++ Fh_br_id, ++ Fh_sigen, ++#ifdef CONFIG_AUFS_INO_T_64 ++ /* support 64bit inode number */ ++ Fh_ino1, ++ Fh_ino2, ++ Fh_dir_ino1, ++ Fh_dir_ino2, ++#else ++ Fh_ino1, ++ Fh_dir_ino1, ++#endif ++ Fh_igen, ++ Fh_h_type, ++ Fh_tail, ++ ++ Fh_ino = Fh_ino1, ++ Fh_dir_ino = Fh_dir_ino1 ++}; ++ ++static int au_test_anon(struct dentry *dentry) ++{ ++ /* note: read d_flags without d_lock */ ++ return !!(dentry->d_flags & DCACHE_DISCONNECTED); ++} ++ ++int au_test_nfsd(void) ++{ ++ int ret; ++ struct task_struct *tsk = current; ++ char comm[sizeof(tsk->comm)]; ++ ++ ret = 0; ++ if (tsk->flags & PF_KTHREAD) { ++ get_task_comm(comm, tsk); ++ ret = !strcmp(comm, "nfsd"); ++ } ++ ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* inode generation external table */ ++ ++void au_xigen_inc(struct inode *inode) ++{ ++ loff_t pos; ++ ssize_t sz; ++ __u32 igen; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ ++ sb = inode->i_sb; ++ AuDebugOn(!au_opt_test(au_mntflags(sb), XINO)); ++ ++ sbinfo = au_sbi(sb); ++ pos = inode->i_ino; ++ pos *= sizeof(igen); ++ igen = inode->i_generation + 1; ++ sz = xino_fwrite(sbinfo->si_xigen, &igen, sizeof(igen), &pos); ++ if (sz == sizeof(igen)) ++ return; /* success */ ++ ++ if (unlikely(sz >= 0)) ++ AuIOErr("xigen error (%zd)\n", sz); ++} ++ ++int au_xigen_new(struct inode *inode) ++{ ++ int err; ++ loff_t pos; ++ ssize_t sz; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ ++ err = 0; ++ /* todo: dirty, at mount time */ ++ if (inode->i_ino == AUFS_ROOT_INO) ++ goto out; ++ sb = inode->i_sb; ++ SiMustAnyLock(sb); ++ if (unlikely(!au_opt_test(au_mntflags(sb), XINO))) ++ goto out; ++ ++ err = -EFBIG; ++ pos = inode->i_ino; ++ if (unlikely(au_loff_max / sizeof(inode->i_generation) - 1 < pos)) { ++ AuIOErr1("too large i%lld\n", pos); ++ goto out; ++ } ++ pos *= sizeof(inode->i_generation); ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ file = sbinfo->si_xigen; ++ BUG_ON(!file); ++ ++ if (vfsub_f_size_read(file) ++ < pos + sizeof(inode->i_generation)) { ++ inode->i_generation = atomic_inc_return(&sbinfo->si_xigen_next); ++ sz = xino_fwrite(file, &inode->i_generation, ++ sizeof(inode->i_generation), &pos); ++ } else ++ sz = xino_fread(file, &inode->i_generation, ++ sizeof(inode->i_generation), &pos); ++ if (sz == sizeof(inode->i_generation)) ++ goto out; /* success */ ++ ++ err = sz; ++ if (unlikely(sz >= 0)) { ++ err = -EIO; ++ AuIOErr("xigen error (%zd)\n", sz); ++ } ++ ++out: ++ return err; ++} ++ ++int au_xigen_set(struct super_block *sb, struct path *path) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ file = au_xino_create2(sb, path, sbinfo->si_xigen); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ err = 0; ++ if (sbinfo->si_xigen) ++ fput(sbinfo->si_xigen); ++ sbinfo->si_xigen = file; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_xigen_clr(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ if (sbinfo->si_xigen) { ++ fput(sbinfo->si_xigen); ++ sbinfo->si_xigen = NULL; ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry *decode_by_ino(struct super_block *sb, ino_t ino, ++ ino_t dir_ino) ++{ ++ struct dentry *dentry, *d; ++ struct inode *inode; ++ unsigned int sigen; ++ ++ dentry = NULL; ++ inode = ilookup(sb, ino); ++ if (!inode) ++ goto out; ++ ++ dentry = ERR_PTR(-ESTALE); ++ sigen = au_sigen(sb); ++ if (unlikely(au_is_bad_inode(inode) ++ || IS_DEADDIR(inode) ++ || sigen != au_iigen(inode, NULL))) ++ goto out_iput; ++ ++ dentry = NULL; ++ if (!dir_ino || S_ISDIR(inode->i_mode)) ++ dentry = d_find_alias(inode); ++ else { ++ spin_lock(&inode->i_lock); ++ hlist_for_each_entry(d, &inode->i_dentry, d_u.d_alias) { ++ spin_lock(&d->d_lock); ++ if (!au_test_anon(d) ++ && d_inode(d->d_parent)->i_ino == dir_ino) { ++ dentry = dget_dlock(d); ++ spin_unlock(&d->d_lock); ++ break; ++ } ++ spin_unlock(&d->d_lock); ++ } ++ spin_unlock(&inode->i_lock); ++ } ++ if (unlikely(dentry && au_digen_test(dentry, sigen))) { ++ /* need to refresh */ ++ dput(dentry); ++ dentry = NULL; ++ } ++ ++out_iput: ++ iput(inode); ++out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* todo: dirty? */ ++/* if exportfs_decode_fh() passed vfsmount*, we could be happy */ ++ ++struct au_compare_mnt_args { ++ /* input */ ++ struct super_block *sb; ++ ++ /* output */ ++ struct vfsmount *mnt; ++}; ++ ++static int au_compare_mnt(struct vfsmount *mnt, void *arg) ++{ ++ struct au_compare_mnt_args *a = arg; ++ ++ if (mnt->mnt_sb != a->sb) ++ return 0; ++ a->mnt = mntget(mnt); ++ return 1; ++} ++ ++static struct vfsmount *au_mnt_get(struct super_block *sb) ++{ ++ int err; ++ struct path root; ++ struct au_compare_mnt_args args = { ++ .sb = sb ++ }; ++ ++ get_fs_root(current->fs, &root); ++ rcu_read_lock(); ++ err = iterate_mounts(au_compare_mnt, &args, root.mnt); ++ rcu_read_unlock(); ++ path_put(&root); ++ AuDebugOn(!err); ++ AuDebugOn(!args.mnt); ++ return args.mnt; ++} ++ ++struct au_nfsd_si_lock { ++ unsigned int sigen; ++ aufs_bindex_t bindex, br_id; ++ unsigned char force_lock; ++}; ++ ++static int si_nfsd_read_lock(struct super_block *sb, ++ struct au_nfsd_si_lock *nsi_lock) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ ++ si_read_lock(sb, AuLock_FLUSH); ++ ++ /* branch id may be wrapped around */ ++ err = 0; ++ bindex = au_br_index(sb, nsi_lock->br_id); ++ if (bindex >= 0 && nsi_lock->sigen + AUFS_BRANCH_MAX > au_sigen(sb)) ++ goto out; /* success */ ++ ++ err = -ESTALE; ++ bindex = -1; ++ if (!nsi_lock->force_lock) ++ si_read_unlock(sb); ++ ++out: ++ nsi_lock->bindex = bindex; ++ return err; ++} ++ ++struct find_name_by_ino { ++ struct dir_context ctx; ++ int called, found; ++ ino_t ino; ++ char *name; ++ int namelen; ++}; ++ ++static int ++find_name_by_ino(struct dir_context *ctx, const char *name, int namelen, ++ loff_t offset, u64 ino, unsigned int d_type) ++{ ++ struct find_name_by_ino *a = container_of(ctx, struct find_name_by_ino, ++ ctx); ++ ++ a->called++; ++ if (a->ino != ino) ++ return 0; ++ ++ memcpy(a->name, name, namelen); ++ a->namelen = namelen; ++ a->found = 1; ++ return 1; ++} ++ ++static struct dentry *au_lkup_by_ino(struct path *path, ino_t ino, ++ struct au_nfsd_si_lock *nsi_lock) ++{ ++ struct dentry *dentry, *parent; ++ struct file *file; ++ struct inode *dir; ++ struct find_name_by_ino arg = { ++ .ctx = { ++ .actor = find_name_by_ino ++ } ++ }; ++ int err; ++ ++ parent = path->dentry; ++ if (nsi_lock) ++ si_read_unlock(parent->d_sb); ++ file = vfsub_dentry_open(path, au_dir_roflags); ++ dentry = (void *)file; ++ if (IS_ERR(file)) ++ goto out; ++ ++ dentry = ERR_PTR(-ENOMEM); ++ arg.name = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!arg.name)) ++ goto out_file; ++ arg.ino = ino; ++ arg.found = 0; ++ do { ++ arg.called = 0; ++ /* smp_mb(); */ ++ err = vfsub_iterate_dir(file, &arg.ctx); ++ } while (!err && !arg.found && arg.called); ++ dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_name; ++ /* instead of ENOENT */ ++ dentry = ERR_PTR(-ESTALE); ++ if (!arg.found) ++ goto out_name; ++ ++ /* do not call vfsub_lkup_one() */ ++ dir = d_inode(parent); ++ dentry = vfsub_lookup_one_len_unlocked(arg.name, path, arg.namelen); ++ AuTraceErrPtr(dentry); ++ if (IS_ERR(dentry)) ++ goto out_name; ++ AuDebugOn(au_test_anon(dentry)); ++ if (unlikely(d_really_is_negative(dentry))) { ++ dput(dentry); ++ dentry = ERR_PTR(-ENOENT); ++ } ++ ++out_name: ++ free_page((unsigned long)arg.name); ++out_file: ++ fput(file); ++out: ++ if (unlikely(nsi_lock ++ && si_nfsd_read_lock(parent->d_sb, nsi_lock) < 0)) ++ if (!IS_ERR(dentry)) { ++ dput(dentry); ++ dentry = ERR_PTR(-ESTALE); ++ } ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++static struct dentry *decode_by_dir_ino(struct super_block *sb, ino_t ino, ++ ino_t dir_ino, ++ struct au_nfsd_si_lock *nsi_lock) ++{ ++ struct dentry *dentry; ++ struct path path; ++ ++ if (dir_ino != AUFS_ROOT_INO) { ++ path.dentry = decode_by_ino(sb, dir_ino, 0); ++ dentry = path.dentry; ++ if (!path.dentry || IS_ERR(path.dentry)) ++ goto out; ++ AuDebugOn(au_test_anon(path.dentry)); ++ } else ++ path.dentry = dget(sb->s_root); ++ ++ path.mnt = au_mnt_get(sb); ++ dentry = au_lkup_by_ino(&path, ino, nsi_lock); ++ path_put(&path); ++ ++out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int h_acceptable(void *expv, struct dentry *dentry) ++{ ++ return 1; ++} ++ ++static char *au_build_path(struct dentry *h_parent, struct path *h_rootpath, ++ char *buf, int len, struct super_block *sb) ++{ ++ char *p; ++ int n; ++ struct path path; ++ ++ p = d_path(h_rootpath, buf, len); ++ if (IS_ERR(p)) ++ goto out; ++ n = strlen(p); ++ ++ path.mnt = h_rootpath->mnt; ++ path.dentry = h_parent; ++ p = d_path(&path, buf, len); ++ if (IS_ERR(p)) ++ goto out; ++ if (n != 1) ++ p += n; ++ ++ path.mnt = au_mnt_get(sb); ++ path.dentry = sb->s_root; ++ p = d_path(&path, buf, len - strlen(p)); ++ mntput(path.mnt); ++ if (IS_ERR(p)) ++ goto out; ++ if (n != 1) ++ p[strlen(p)] = '/'; ++ ++out: ++ AuTraceErrPtr(p); ++ return p; ++} ++ ++static ++struct dentry *decode_by_path(struct super_block *sb, ino_t ino, __u32 *fh, ++ int fh_len, struct au_nfsd_si_lock *nsi_lock) ++{ ++ struct dentry *dentry, *h_parent, *root; ++ struct super_block *h_sb; ++ char *pathname, *p; ++ struct vfsmount *h_mnt; ++ struct au_branch *br; ++ int err; ++ struct path path; ++ ++ br = au_sbr(sb, nsi_lock->bindex); ++ h_mnt = au_br_mnt(br); ++ h_sb = h_mnt->mnt_sb; ++ /* todo: call lower fh_to_dentry()? fh_to_parent()? */ ++ lockdep_off(); ++ h_parent = exportfs_decode_fh(h_mnt, (void *)(fh + Fh_tail), ++ fh_len - Fh_tail, fh[Fh_h_type], ++ h_acceptable, /*context*/NULL); ++ lockdep_on(); ++ dentry = h_parent; ++ if (unlikely(!h_parent || IS_ERR(h_parent))) { ++ AuWarn1("%s decode_fh failed, %ld\n", ++ au_sbtype(h_sb), PTR_ERR(h_parent)); ++ goto out; ++ } ++ dentry = NULL; ++ if (unlikely(au_test_anon(h_parent))) { ++ AuWarn1("%s decode_fh returned a disconnected dentry\n", ++ au_sbtype(h_sb)); ++ goto out_h_parent; ++ } ++ ++ dentry = ERR_PTR(-ENOMEM); ++ pathname = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!pathname)) ++ goto out_h_parent; ++ ++ root = sb->s_root; ++ path.mnt = h_mnt; ++ di_read_lock_parent(root, !AuLock_IR); ++ path.dentry = au_h_dptr(root, nsi_lock->bindex); ++ di_read_unlock(root, !AuLock_IR); ++ p = au_build_path(h_parent, &path, pathname, PAGE_SIZE, sb); ++ dentry = (void *)p; ++ if (IS_ERR(p)) ++ goto out_pathname; ++ ++ si_read_unlock(sb); ++ err = vfsub_kern_path(p, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); ++ dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_relock; ++ ++ dentry = ERR_PTR(-ENOENT); ++ AuDebugOn(au_test_anon(path.dentry)); ++ if (unlikely(d_really_is_negative(path.dentry))) ++ goto out_path; ++ ++ if (ino != d_inode(path.dentry)->i_ino) ++ dentry = au_lkup_by_ino(&path, ino, /*nsi_lock*/NULL); ++ else ++ dentry = dget(path.dentry); ++ ++out_path: ++ path_put(&path); ++out_relock: ++ if (unlikely(si_nfsd_read_lock(sb, nsi_lock) < 0)) ++ if (!IS_ERR(dentry)) { ++ dput(dentry); ++ dentry = ERR_PTR(-ESTALE); ++ } ++out_pathname: ++ free_page((unsigned long)pathname); ++out_h_parent: ++ dput(h_parent); ++out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry * ++aufs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, ++ int fh_type) ++{ ++ struct dentry *dentry; ++ __u32 *fh = fid->raw; ++ struct au_branch *br; ++ ino_t ino, dir_ino; ++ struct au_nfsd_si_lock nsi_lock = { ++ .force_lock = 0 ++ }; ++ ++ dentry = ERR_PTR(-ESTALE); ++ /* it should never happen, but the file handle is unreliable */ ++ if (unlikely(fh_len < Fh_tail)) ++ goto out; ++ nsi_lock.sigen = fh[Fh_sigen]; ++ nsi_lock.br_id = fh[Fh_br_id]; ++ ++ /* branch id may be wrapped around */ ++ br = NULL; ++ if (unlikely(si_nfsd_read_lock(sb, &nsi_lock))) ++ goto out; ++ nsi_lock.force_lock = 1; ++ ++ /* is this inode still cached? */ ++ ino = decode_ino(fh + Fh_ino); ++ /* it should never happen */ ++ if (unlikely(ino == AUFS_ROOT_INO)) ++ goto out_unlock; ++ ++ dir_ino = decode_ino(fh + Fh_dir_ino); ++ dentry = decode_by_ino(sb, ino, dir_ino); ++ if (IS_ERR(dentry)) ++ goto out_unlock; ++ if (dentry) ++ goto accept; ++ ++ /* is the parent dir cached? */ ++ br = au_sbr(sb, nsi_lock.bindex); ++ au_lcnt_inc(&br->br_nfiles); ++ dentry = decode_by_dir_ino(sb, ino, dir_ino, &nsi_lock); ++ if (IS_ERR(dentry)) ++ goto out_unlock; ++ if (dentry) ++ goto accept; ++ ++ /* lookup path */ ++ dentry = decode_by_path(sb, ino, fh, fh_len, &nsi_lock); ++ if (IS_ERR(dentry)) ++ goto out_unlock; ++ if (unlikely(!dentry)) ++ /* todo?: make it ESTALE */ ++ goto out_unlock; ++ ++accept: ++ if (!au_digen_test(dentry, au_sigen(sb)) ++ && d_inode(dentry)->i_generation == fh[Fh_igen]) ++ goto out_unlock; /* success */ ++ ++ dput(dentry); ++ dentry = ERR_PTR(-ESTALE); ++out_unlock: ++ if (br) ++ au_lcnt_dec(&br->br_nfiles); ++ si_read_unlock(sb); ++out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++#if 0 /* reserved for future use */ ++/* support subtreecheck option */ ++static struct dentry *aufs_fh_to_parent(struct super_block *sb, struct fid *fid, ++ int fh_len, int fh_type) ++{ ++ struct dentry *parent; ++ __u32 *fh = fid->raw; ++ ino_t dir_ino; ++ ++ dir_ino = decode_ino(fh + Fh_dir_ino); ++ parent = decode_by_ino(sb, dir_ino, 0); ++ if (IS_ERR(parent)) ++ goto out; ++ if (!parent) ++ parent = decode_by_path(sb, au_br_index(sb, fh[Fh_br_id]), ++ dir_ino, fh, fh_len); ++ ++out: ++ AuTraceErrPtr(parent); ++ return parent; ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_encode_fh(struct inode *inode, __u32 *fh, int *max_len, ++ struct inode *dir) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct super_block *sb, *h_sb; ++ struct dentry *dentry, *parent, *h_parent; ++ struct inode *h_dir; ++ struct au_branch *br; ++ ++ err = -ENOSPC; ++ if (unlikely(*max_len <= Fh_tail)) { ++ AuWarn1("NFSv2 client (max_len %d)?\n", *max_len); ++ goto out; ++ } ++ ++ err = FILEID_ROOT; ++ if (inode->i_ino == AUFS_ROOT_INO) { ++ AuDebugOn(inode->i_ino != AUFS_ROOT_INO); ++ goto out; ++ } ++ ++ h_parent = NULL; ++ sb = inode->i_sb; ++ err = si_read_lock(sb, AuLock_FLUSH); ++ if (unlikely(err)) ++ goto out; ++ ++#ifdef CONFIG_AUFS_DEBUG ++ if (unlikely(!au_opt_test(au_mntflags(sb), XINO))) ++ AuWarn1("NFS-exporting requires xino\n"); ++#endif ++ err = -EIO; ++ parent = NULL; ++ ii_read_lock_child(inode); ++ bindex = au_ibtop(inode); ++ if (!dir) { ++ dentry = d_find_any_alias(inode); ++ if (unlikely(!dentry)) ++ goto out_unlock; ++ AuDebugOn(au_test_anon(dentry)); ++ parent = dget_parent(dentry); ++ dput(dentry); ++ if (unlikely(!parent)) ++ goto out_unlock; ++ if (d_really_is_positive(parent)) ++ dir = d_inode(parent); ++ } ++ ++ ii_read_lock_parent(dir); ++ h_dir = au_h_iptr(dir, bindex); ++ ii_read_unlock(dir); ++ if (unlikely(!h_dir)) ++ goto out_parent; ++ h_parent = d_find_any_alias(h_dir); ++ if (unlikely(!h_parent)) ++ goto out_hparent; ++ ++ err = -EPERM; ++ br = au_sbr(sb, bindex); ++ h_sb = au_br_sb(br); ++ if (unlikely(!h_sb->s_export_op)) { ++ AuErr1("%s branch is not exportable\n", au_sbtype(h_sb)); ++ goto out_hparent; ++ } ++ ++ fh[Fh_br_id] = br->br_id; ++ fh[Fh_sigen] = au_sigen(sb); ++ encode_ino(fh + Fh_ino, inode->i_ino); ++ encode_ino(fh + Fh_dir_ino, dir->i_ino); ++ fh[Fh_igen] = inode->i_generation; ++ ++ *max_len -= Fh_tail; ++ fh[Fh_h_type] = exportfs_encode_fh(h_parent, (void *)(fh + Fh_tail), ++ max_len, ++ /*connectable or subtreecheck*/0); ++ err = fh[Fh_h_type]; ++ *max_len += Fh_tail; ++ /* todo: macros? */ ++ if (err != FILEID_INVALID) ++ err = 99; ++ else ++ AuWarn1("%s encode_fh failed\n", au_sbtype(h_sb)); ++ ++out_hparent: ++ dput(h_parent); ++out_parent: ++ dput(parent); ++out_unlock: ++ ii_read_unlock(inode); ++ si_read_unlock(sb); ++out: ++ if (unlikely(err < 0)) ++ err = FILEID_INVALID; ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_commit_metadata(struct inode *inode) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct super_block *sb; ++ struct inode *h_inode; ++ int (*f)(struct inode *inode); ++ ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ii_write_lock_child(inode); ++ bindex = au_ibtop(inode); ++ AuDebugOn(bindex < 0); ++ h_inode = au_h_iptr(inode, bindex); ++ ++ f = h_inode->i_sb->s_export_op->commit_metadata; ++ if (f) ++ err = f(h_inode); ++ else ++ err = sync_inode_metadata(h_inode, /*wait*/1); ++ ++ au_cpup_attr_timesizes(inode); ++ ii_write_unlock(inode); ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct export_operations aufs_export_op = { ++ .fh_to_dentry = aufs_fh_to_dentry, ++ /* .fh_to_parent = aufs_fh_to_parent, */ ++ .encode_fh = aufs_encode_fh, ++ .commit_metadata = aufs_commit_metadata ++}; ++ ++void au_export_init(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ __u32 u; ++ ++ BUILD_BUG_ON_MSG(IS_BUILTIN(CONFIG_AUFS_FS) ++ && IS_MODULE(CONFIG_EXPORTFS), ++ AUFS_NAME ": unsupported configuration " ++ "CONFIG_EXPORTFS=m and CONFIG_AUFS_FS=y"); ++ ++ sb->s_export_op = &aufs_export_op; ++ sbinfo = au_sbi(sb); ++ sbinfo->si_xigen = NULL; ++ get_random_bytes(&u, sizeof(u)); ++ BUILD_BUG_ON(sizeof(u) != sizeof(int)); ++ atomic_set(&sbinfo->si_xigen_next, u); ++} +diff -Nurp linux-5.15.37/fs/aufs/fhsm.c linux-5.15.37-aufs/fs/aufs/fhsm.c +--- linux-5.15.37/fs/aufs/fhsm.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/fhsm.c 2022-04-08 20:22:30.612616475 +0300 +@@ -0,0 +1,413 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2011-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * File-based Hierarchy Storage Management ++ */ ++ ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++static aufs_bindex_t au_fhsm_bottom(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ AuDebugOn(!fhsm); ++ return fhsm->fhsm_bottom; ++} ++ ++void au_fhsm_set_bottom(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ AuDebugOn(!fhsm); ++ fhsm->fhsm_bottom = bindex; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_fhsm_test_jiffy(struct au_sbinfo *sbinfo, struct au_branch *br) ++{ ++ struct au_br_fhsm *bf; ++ ++ bf = br->br_fhsm; ++ MtxMustLock(&bf->bf_lock); ++ ++ return !bf->bf_readable ++ || time_after(jiffies, ++ bf->bf_jiffy + sbinfo->si_fhsm.fhsm_expire); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_fhsm_notify(struct super_block *sb, int val) ++{ ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ if (au_fhsm_pid(fhsm) ++ && atomic_read(&fhsm->fhsm_readable) != -1) { ++ atomic_set(&fhsm->fhsm_readable, val); ++ if (val) ++ wake_up(&fhsm->fhsm_wqh); ++ } ++} ++ ++static int au_fhsm_stfs(struct super_block *sb, aufs_bindex_t bindex, ++ struct aufs_stfs *rstfs, int do_lock, int do_notify) ++{ ++ int err; ++ struct au_branch *br; ++ struct au_br_fhsm *bf; ++ ++ br = au_sbr(sb, bindex); ++ AuDebugOn(au_br_rdonly(br)); ++ bf = br->br_fhsm; ++ AuDebugOn(!bf); ++ ++ if (do_lock) ++ mutex_lock(&bf->bf_lock); ++ else ++ MtxMustLock(&bf->bf_lock); ++ ++ /* sb->s_root for NFS is unreliable */ ++ err = au_br_stfs(br, &bf->bf_stfs); ++ if (unlikely(err)) { ++ AuErr1("FHSM failed (%d), b%d, ignored.\n", bindex, err); ++ goto out; ++ } ++ ++ bf->bf_jiffy = jiffies; ++ bf->bf_readable = 1; ++ if (do_notify) ++ au_fhsm_notify(sb, /*val*/1); ++ if (rstfs) ++ *rstfs = bf->bf_stfs; ++ ++out: ++ if (do_lock) ++ mutex_unlock(&bf->bf_lock); ++ au_fhsm_notify(sb, /*val*/1); ++ ++ return err; ++} ++ ++void au_fhsm_wrote(struct super_block *sb, aufs_bindex_t bindex, int force) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ struct au_branch *br; ++ struct au_br_fhsm *bf; ++ ++ AuDbg("b%d, force %d\n", bindex, force); ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ if (!au_ftest_si(sbinfo, FHSM) ++ || fhsm->fhsm_bottom == bindex) ++ return; ++ ++ br = au_sbr(sb, bindex); ++ bf = br->br_fhsm; ++ AuDebugOn(!bf); ++ mutex_lock(&bf->bf_lock); ++ if (force ++ || au_fhsm_pid(fhsm) ++ || au_fhsm_test_jiffy(sbinfo, br)) ++ err = au_fhsm_stfs(sb, bindex, /*rstfs*/NULL, /*do_lock*/0, ++ /*do_notify*/1); ++ mutex_unlock(&bf->bf_lock); ++} ++ ++void au_fhsm_wrote_all(struct super_block *sb, int force) ++{ ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ /* exclude the bottom */ ++ bbot = au_fhsm_bottom(sb); ++ for (bindex = 0; bindex < bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm)) ++ au_fhsm_wrote(sb, bindex, force); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static __poll_t au_fhsm_poll(struct file *file, struct poll_table_struct *wait) ++{ ++ __poll_t mask; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ mask = 0; ++ sbinfo = file->private_data; ++ fhsm = &sbinfo->si_fhsm; ++ poll_wait(file, &fhsm->fhsm_wqh, wait); ++ if (atomic_read(&fhsm->fhsm_readable)) ++ mask = EPOLLIN /* | EPOLLRDNORM */; ++ ++ if (!mask) ++ AuDbg("mask 0x%x\n", mask); ++ return mask; ++} ++ ++static int au_fhsm_do_read_one(struct aufs_stbr __user *stbr, ++ struct aufs_stfs *stfs, __s16 brid) ++{ ++ int err; ++ ++ err = copy_to_user(&stbr->stfs, stfs, sizeof(*stfs)); ++ if (!err) ++ err = __put_user(brid, &stbr->brid); ++ if (unlikely(err)) ++ err = -EFAULT; ++ ++ return err; ++} ++ ++static ssize_t au_fhsm_do_read(struct super_block *sb, ++ struct aufs_stbr __user *stbr, size_t count) ++{ ++ ssize_t err; ++ int nstbr; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ struct au_br_fhsm *bf; ++ ++ /* except the bottom branch */ ++ err = 0; ++ nstbr = 0; ++ bbot = au_fhsm_bottom(sb); ++ for (bindex = 0; !err && bindex < bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!au_br_fhsm(br->br_perm)) ++ continue; ++ ++ bf = br->br_fhsm; ++ mutex_lock(&bf->bf_lock); ++ if (bf->bf_readable) { ++ err = -EFAULT; ++ if (count >= sizeof(*stbr)) ++ err = au_fhsm_do_read_one(stbr++, &bf->bf_stfs, ++ br->br_id); ++ if (!err) { ++ bf->bf_readable = 0; ++ count -= sizeof(*stbr); ++ nstbr++; ++ } ++ } ++ mutex_unlock(&bf->bf_lock); ++ } ++ if (!err) ++ err = sizeof(*stbr) * nstbr; ++ ++ return err; ++} ++ ++static ssize_t au_fhsm_read(struct file *file, char __user *buf, size_t count, ++ loff_t *pos) ++{ ++ ssize_t err; ++ int readable; ++ aufs_bindex_t nfhsm, bindex, bbot; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ struct au_branch *br; ++ struct super_block *sb; ++ ++ err = 0; ++ sbinfo = file->private_data; ++ fhsm = &sbinfo->si_fhsm; ++need_data: ++ spin_lock_irq(&fhsm->fhsm_wqh.lock); ++ if (!atomic_read(&fhsm->fhsm_readable)) { ++ if (vfsub_file_flags(file) & O_NONBLOCK) ++ err = -EAGAIN; ++ else ++ err = wait_event_interruptible_locked_irq ++ (fhsm->fhsm_wqh, ++ atomic_read(&fhsm->fhsm_readable)); ++ } ++ spin_unlock_irq(&fhsm->fhsm_wqh.lock); ++ if (unlikely(err)) ++ goto out; ++ ++ /* sb may already be dead */ ++ au_rw_read_lock(&sbinfo->si_rwsem); ++ readable = atomic_read(&fhsm->fhsm_readable); ++ if (readable > 0) { ++ sb = sbinfo->si_sb; ++ AuDebugOn(!sb); ++ /* exclude the bottom branch */ ++ nfhsm = 0; ++ bbot = au_fhsm_bottom(sb); ++ for (bindex = 0; bindex < bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm)) ++ nfhsm++; ++ } ++ err = -EMSGSIZE; ++ if (nfhsm * sizeof(struct aufs_stbr) <= count) { ++ atomic_set(&fhsm->fhsm_readable, 0); ++ err = au_fhsm_do_read(sbinfo->si_sb, (void __user *)buf, ++ count); ++ } ++ } ++ au_rw_read_unlock(&sbinfo->si_rwsem); ++ if (!readable) ++ goto need_data; ++ ++out: ++ return err; ++} ++ ++static int au_fhsm_release(struct inode *inode, struct file *file) ++{ ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ /* sb may already be dead */ ++ sbinfo = file->private_data; ++ fhsm = &sbinfo->si_fhsm; ++ spin_lock(&fhsm->fhsm_spin); ++ fhsm->fhsm_pid = 0; ++ spin_unlock(&fhsm->fhsm_spin); ++ kobject_put(&sbinfo->si_kobj); ++ ++ return 0; ++} ++ ++static const struct file_operations au_fhsm_fops = { ++ .owner = THIS_MODULE, ++ .llseek = noop_llseek, ++ .read = au_fhsm_read, ++ .poll = au_fhsm_poll, ++ .release = au_fhsm_release ++}; ++ ++int au_fhsm_fd(struct super_block *sb, int oflags) ++{ ++ int err, fd; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ err = -EPERM; ++ if (unlikely(!capable(CAP_SYS_ADMIN))) ++ goto out; ++ ++ err = -EINVAL; ++ if (unlikely(oflags & ~(O_CLOEXEC | O_NONBLOCK))) ++ goto out; ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ spin_lock(&fhsm->fhsm_spin); ++ if (!fhsm->fhsm_pid) ++ fhsm->fhsm_pid = current->pid; ++ else ++ err = -EBUSY; ++ spin_unlock(&fhsm->fhsm_spin); ++ if (unlikely(err)) ++ goto out; ++ ++ oflags |= O_RDONLY; ++ /* oflags |= FMODE_NONOTIFY; */ ++ fd = anon_inode_getfd("[aufs_fhsm]", &au_fhsm_fops, sbinfo, oflags); ++ err = fd; ++ if (unlikely(fd < 0)) ++ goto out_pid; ++ ++ /* succeed regardless 'fhsm' status */ ++ kobject_get(&sbinfo->si_kobj); ++ si_noflush_read_lock(sb); ++ if (au_ftest_si(sbinfo, FHSM)) ++ au_fhsm_wrote_all(sb, /*force*/0); ++ si_read_unlock(sb); ++ goto out; /* success */ ++ ++out_pid: ++ spin_lock(&fhsm->fhsm_spin); ++ fhsm->fhsm_pid = 0; ++ spin_unlock(&fhsm->fhsm_spin); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_fhsm_br_alloc(struct au_branch *br) ++{ ++ int err; ++ ++ err = 0; ++ br->br_fhsm = kmalloc(sizeof(*br->br_fhsm), GFP_NOFS); ++ if (br->br_fhsm) ++ au_br_fhsm_init(br->br_fhsm); ++ else ++ err = -ENOMEM; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_fhsm_fin(struct super_block *sb) ++{ ++ au_fhsm_notify(sb, /*val*/-1); ++} ++ ++void au_fhsm_init(struct au_sbinfo *sbinfo) ++{ ++ struct au_fhsm *fhsm; ++ ++ fhsm = &sbinfo->si_fhsm; ++ spin_lock_init(&fhsm->fhsm_spin); ++ init_waitqueue_head(&fhsm->fhsm_wqh); ++ atomic_set(&fhsm->fhsm_readable, 0); ++ fhsm->fhsm_expire ++ = msecs_to_jiffies(AUFS_FHSM_CACHE_DEF_SEC * MSEC_PER_SEC); ++ fhsm->fhsm_bottom = -1; ++} ++ ++void au_fhsm_set(struct au_sbinfo *sbinfo, unsigned int sec) ++{ ++ sbinfo->si_fhsm.fhsm_expire ++ = msecs_to_jiffies(sec * MSEC_PER_SEC); ++} ++ ++void au_fhsm_show(struct seq_file *seq, struct au_sbinfo *sbinfo) ++{ ++ unsigned int u; ++ ++ if (!au_ftest_si(sbinfo, FHSM)) ++ return; ++ ++ u = jiffies_to_msecs(sbinfo->si_fhsm.fhsm_expire) / MSEC_PER_SEC; ++ if (u != AUFS_FHSM_CACHE_DEF_SEC) ++ seq_printf(seq, ",fhsm_sec=%u", u); ++} +diff -Nurp linux-5.15.37/fs/aufs/file.c linux-5.15.37-aufs/fs/aufs/file.c +--- linux-5.15.37/fs/aufs/file.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/file.c 2022-04-08 20:22:30.613616524 +0300 +@@ -0,0 +1,850 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * handling file/dir, and address_space operation ++ */ ++ ++#ifdef CONFIG_AUFS_DEBUG ++#include ++#endif ++#include ++#include "aufs.h" ++ ++/* drop flags for writing */ ++unsigned int au_file_roflags(unsigned int flags) ++{ ++ flags &= ~(O_WRONLY | O_RDWR | O_APPEND | O_CREAT | O_TRUNC); ++ flags |= O_RDONLY | O_NOATIME; ++ return flags; ++} ++ ++/* common functions to regular file and dir */ ++struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, ++ struct file *file, int force_wr) ++{ ++ struct file *h_file; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct path h_path; ++ int err; ++ ++ /* a race condition can happen between open and unlink/rmdir */ ++ h_file = ERR_PTR(-ENOENT); ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (au_test_nfsd() && (!h_dentry || d_is_negative(h_dentry))) ++ goto out; ++ h_inode = d_inode(h_dentry); ++ spin_lock(&h_dentry->d_lock); ++ err = (!d_unhashed(dentry) && d_unlinked(h_dentry)) ++ /* || !d_inode(dentry)->i_nlink */ ++ ; ++ spin_unlock(&h_dentry->d_lock); ++ if (unlikely(err)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, bindex); ++ err = au_br_test_oflag(flags, br); ++ h_file = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ /* drop flags for writing */ ++ if (au_test_ro(sb, bindex, d_inode(dentry))) { ++ if (force_wr && !(flags & O_WRONLY)) ++ force_wr = 0; ++ flags = au_file_roflags(flags); ++ if (force_wr) { ++ h_file = ERR_PTR(-EROFS); ++ flags = au_file_roflags(flags); ++ if (unlikely(vfsub_native_ro(h_inode) ++ || IS_APPEND(h_inode))) ++ goto out; ++ flags &= ~O_ACCMODE; ++ flags |= O_WRONLY; ++ } ++ } ++ flags &= ~O_CREAT; ++ au_lcnt_inc(&br->br_nfiles); ++ h_path.dentry = h_dentry; ++ h_path.mnt = au_br_mnt(br); ++ h_file = vfsub_dentry_open(&h_path, flags); ++ if (IS_ERR(h_file)) ++ goto out_br; ++ ++ if (flags & __FMODE_EXEC) { ++ err = deny_write_access(h_file); ++ if (unlikely(err)) { ++ fput(h_file); ++ h_file = ERR_PTR(err); ++ goto out_br; ++ } ++ } ++ fsnotify_open(h_file); ++ goto out; /* success */ ++ ++out_br: ++ au_lcnt_dec(&br->br_nfiles); ++out: ++ return h_file; ++} ++ ++static int au_cmoo(struct dentry *dentry) ++{ ++ int err, cmoo, matched; ++ unsigned int udba; ++ struct path h_path; ++ struct au_pin pin; ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = -1, ++ .bsrc = -1, ++ .len = -1, ++ .pin = &pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ struct inode *delegated; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ pid_t pid; ++ struct au_branch *br; ++ struct dentry *parent; ++ struct au_hinode *hdir; ++ ++ DiMustWriteLock(dentry); ++ IiMustWriteLock(d_inode(dentry)); ++ ++ err = 0; ++ if (IS_ROOT(dentry)) ++ goto out; ++ cpg.bsrc = au_dbtop(dentry); ++ if (!cpg.bsrc) ++ goto out; ++ ++ sb = dentry->d_sb; ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ pid = au_fhsm_pid(fhsm); ++ rcu_read_lock(); ++ matched = (pid ++ && (current->pid == pid ++ || rcu_dereference(current->real_parent)->pid == pid)); ++ rcu_read_unlock(); ++ if (matched) ++ goto out; ++ ++ br = au_sbr(sb, cpg.bsrc); ++ cmoo = au_br_cmoo(br->br_perm); ++ if (!cmoo) ++ goto out; ++ if (!d_is_reg(dentry)) ++ cmoo &= AuBrAttr_COO_ALL; ++ if (!cmoo) ++ goto out; ++ ++ parent = dget_parent(dentry); ++ di_write_lock_parent(parent); ++ err = au_wbr_do_copyup_bu(dentry, cpg.bsrc - 1); ++ cpg.bdst = err; ++ if (unlikely(err < 0)) { ++ err = 0; /* there is no upper writable branch */ ++ goto out_dgrade; ++ } ++ AuDbg("bsrc %d, bdst %d\n", cpg.bsrc, cpg.bdst); ++ ++ /* do not respect the coo attrib for the target branch */ ++ err = au_cpup_dirs(dentry, cpg.bdst); ++ if (unlikely(err)) ++ goto out_dgrade; ++ ++ di_downgrade_lock(parent, AuLock_IR); ++ udba = au_opt_udba(sb); ++ err = au_pin(&pin, dentry, cpg.bdst, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&pin); ++ if (unlikely(err)) ++ goto out_parent; ++ if (!(cmoo & AuBrWAttr_MOO)) ++ goto out_parent; /* success */ ++ ++ err = au_pin(&pin, dentry, cpg.bsrc, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ h_path.mnt = au_br_mnt(br); ++ h_path.dentry = au_h_dptr(dentry, cpg.bsrc); ++ hdir = au_hi(d_inode(parent), cpg.bsrc); ++ delegated = NULL; ++ err = vfsub_unlink(hdir->hi_inode, &h_path, &delegated, /*force*/1); ++ au_unpin(&pin); ++ /* todo: keep h_dentry or not? */ ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ if (unlikely(err)) { ++ pr_err("unlink %pd after coo failed (%d), ignored\n", ++ dentry, err); ++ err = 0; ++ } ++ goto out_parent; /* success */ ++ ++out_dgrade: ++ di_downgrade_lock(parent, AuLock_IR); ++out_parent: ++ di_read_unlock(parent, AuLock_IR); ++ dput(parent); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_do_open(struct file *file, struct au_do_open_args *args) ++{ ++ int err, aopen = args->aopen; ++ struct dentry *dentry; ++ struct au_finfo *finfo; ++ ++ if (!aopen) ++ err = au_finfo_init(file, args->fidir); ++ else { ++ lockdep_off(); ++ err = au_finfo_init(file, args->fidir); ++ lockdep_on(); ++ } ++ if (unlikely(err)) ++ goto out; ++ ++ dentry = file->f_path.dentry; ++ AuDebugOn(IS_ERR_OR_NULL(dentry)); ++ di_write_lock_child(dentry); ++ err = au_cmoo(dentry); ++ di_downgrade_lock(dentry, AuLock_IR); ++ if (!err) { ++ if (!aopen) ++ err = args->open(file, vfsub_file_flags(file), NULL); ++ else { ++ lockdep_off(); ++ err = args->open(file, vfsub_file_flags(file), ++ args->h_file); ++ lockdep_on(); ++ } ++ } ++ di_read_unlock(dentry, AuLock_IR); ++ ++ finfo = au_fi(file); ++ if (!err) { ++ finfo->fi_file = file; ++ au_hbl_add(&finfo->fi_hlist, ++ &au_sbi(file->f_path.dentry->d_sb)->si_files); ++ } ++ if (!aopen) ++ fi_write_unlock(file); ++ else { ++ lockdep_off(); ++ fi_write_unlock(file); ++ lockdep_on(); ++ } ++ if (unlikely(err)) { ++ finfo->fi_hdir = NULL; ++ au_finfo_fin(file); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_reopen_nondir(struct file *file) ++{ ++ int err; ++ aufs_bindex_t btop; ++ struct dentry *dentry; ++ struct au_branch *br; ++ struct file *h_file, *h_file_tmp; ++ ++ dentry = file->f_path.dentry; ++ btop = au_dbtop(dentry); ++ br = au_sbr(dentry->d_sb, btop); ++ h_file_tmp = NULL; ++ if (au_fbtop(file) == btop) { ++ h_file = au_hf_top(file); ++ if (file->f_mode == h_file->f_mode) ++ return 0; /* success */ ++ h_file_tmp = h_file; ++ get_file(h_file_tmp); ++ au_lcnt_inc(&br->br_nfiles); ++ au_set_h_fptr(file, btop, NULL); ++ } ++ AuDebugOn(au_fi(file)->fi_hdir); ++ /* ++ * it can happen ++ * file exists on both of rw and ro ++ * open --> dbtop and fbtop are both 0 ++ * prepend a branch as rw, "rw" become ro ++ * remove rw/file ++ * delete the top branch, "rw" becomes rw again ++ * --> dbtop is 1, fbtop is still 0 ++ * write --> fbtop is 0 but dbtop is 1 ++ */ ++ /* AuDebugOn(au_fbtop(file) < btop); */ ++ ++ h_file = au_h_open(dentry, btop, vfsub_file_flags(file) & ~O_TRUNC, ++ file, /*force_wr*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) { ++ if (h_file_tmp) { ++ /* revert */ ++ au_set_h_fptr(file, btop, h_file_tmp); ++ h_file_tmp = NULL; ++ } ++ goto out; /* todo: close all? */ ++ } ++ ++ err = 0; ++ au_set_fbtop(file, btop); ++ au_set_h_fptr(file, btop, h_file); ++ au_update_figen(file); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ ++out: ++ if (h_file_tmp) { ++ fput(h_file_tmp); ++ au_lcnt_dec(&br->br_nfiles); ++ } ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_reopen_wh(struct file *file, aufs_bindex_t btgt, ++ struct dentry *hi_wh) ++{ ++ int err; ++ aufs_bindex_t btop; ++ struct au_dinfo *dinfo; ++ struct dentry *h_dentry; ++ struct au_hdentry *hdp; ++ ++ dinfo = au_di(file->f_path.dentry); ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ btop = dinfo->di_btop; ++ dinfo->di_btop = btgt; ++ hdp = au_hdentry(dinfo, btgt); ++ h_dentry = hdp->hd_dentry; ++ hdp->hd_dentry = hi_wh; ++ err = au_reopen_nondir(file); ++ hdp->hd_dentry = h_dentry; ++ dinfo->di_btop = btop; ++ ++ return err; ++} ++ ++static int au_ready_to_write_wh(struct file *file, loff_t len, ++ aufs_bindex_t bcpup, struct au_pin *pin) ++{ ++ int err; ++ struct inode *inode, *h_inode; ++ struct dentry *h_dentry, *hi_wh; ++ struct au_cp_generic cpg = { ++ .dentry = file->f_path.dentry, ++ .bdst = bcpup, ++ .bsrc = -1, ++ .len = len, ++ .pin = pin ++ }; ++ ++ au_update_dbtop(cpg.dentry); ++ inode = d_inode(cpg.dentry); ++ h_inode = NULL; ++ if (au_dbtop(cpg.dentry) <= bcpup ++ && au_dbbot(cpg.dentry) >= bcpup) { ++ h_dentry = au_h_dptr(cpg.dentry, bcpup); ++ if (h_dentry && d_is_positive(h_dentry)) ++ h_inode = d_inode(h_dentry); ++ } ++ hi_wh = au_hi_wh(inode, bcpup); ++ if (!hi_wh && !h_inode) ++ err = au_sio_cpup_wh(&cpg, file); ++ else ++ /* already copied-up after unlink */ ++ err = au_reopen_wh(file, bcpup, hi_wh); ++ ++ if (!err ++ && (inode->i_nlink > 1 ++ || (inode->i_state & I_LINKABLE)) ++ && au_opt_test(au_mntflags(cpg.dentry->d_sb), PLINK)) ++ au_plink_append(inode, bcpup, au_h_dptr(cpg.dentry, bcpup)); ++ ++ return err; ++} ++ ++/* ++ * prepare the @file for writing. ++ */ ++int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin) ++{ ++ int err; ++ aufs_bindex_t dbtop; ++ struct dentry *parent; ++ struct inode *inode; ++ struct super_block *sb; ++ struct file *h_file; ++ struct au_cp_generic cpg = { ++ .dentry = file->f_path.dentry, ++ .bdst = -1, ++ .bsrc = -1, ++ .len = len, ++ .pin = pin, ++ .flags = AuCpup_DTIME ++ }; ++ ++ sb = cpg.dentry->d_sb; ++ inode = d_inode(cpg.dentry); ++ cpg.bsrc = au_fbtop(file); ++ err = au_test_ro(sb, cpg.bsrc, inode); ++ if (!err && (au_hf_top(file)->f_mode & FMODE_WRITE)) { ++ err = au_pin(pin, cpg.dentry, cpg.bsrc, AuOpt_UDBA_NONE, ++ /*flags*/0); ++ goto out; ++ } ++ ++ /* need to cpup or reopen */ ++ parent = dget_parent(cpg.dentry); ++ di_write_lock_parent(parent); ++ err = AuWbrCopyup(au_sbi(sb), cpg.dentry); ++ cpg.bdst = err; ++ if (unlikely(err < 0)) ++ goto out_dgrade; ++ err = 0; ++ ++ if (!d_unhashed(cpg.dentry) && !au_h_dptr(parent, cpg.bdst)) { ++ err = au_cpup_dirs(cpg.dentry, cpg.bdst); ++ if (unlikely(err)) ++ goto out_dgrade; ++ } ++ ++ err = au_pin(pin, cpg.dentry, cpg.bdst, AuOpt_UDBA_NONE, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_dgrade; ++ ++ dbtop = au_dbtop(cpg.dentry); ++ if (dbtop <= cpg.bdst) ++ cpg.bsrc = cpg.bdst; ++ ++ if (dbtop <= cpg.bdst /* just reopen */ ++ || !d_unhashed(cpg.dentry) /* copyup and reopen */ ++ ) { ++ h_file = au_h_open_pre(cpg.dentry, cpg.bsrc, /*force_wr*/0); ++ if (IS_ERR(h_file)) ++ err = PTR_ERR(h_file); ++ else { ++ di_downgrade_lock(parent, AuLock_IR); ++ if (dbtop > cpg.bdst) ++ err = au_sio_cpup_simple(&cpg); ++ if (!err) ++ err = au_reopen_nondir(file); ++ au_h_open_post(cpg.dentry, cpg.bsrc, h_file); ++ } ++ } else { /* copyup as wh and reopen */ ++ /* ++ * since writable hfsplus branch is not supported, ++ * h_open_pre/post() are unnecessary. ++ */ ++ err = au_ready_to_write_wh(file, len, cpg.bdst, pin); ++ di_downgrade_lock(parent, AuLock_IR); ++ } ++ ++ if (!err) { ++ au_pin_set_parent_lflag(pin, /*lflag*/0); ++ goto out_dput; /* success */ ++ } ++ au_unpin(pin); ++ goto out_unlock; ++ ++out_dgrade: ++ di_downgrade_lock(parent, AuLock_IR); ++out_unlock: ++ di_read_unlock(parent, AuLock_IR); ++out_dput: ++ dput(parent); ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_do_flush(struct file *file, fl_owner_t id, ++ int (*flush)(struct file *file, fl_owner_t id)) ++{ ++ int err; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ si_noflush_read_lock(sb); ++ fi_read_lock(file); ++ ii_read_lock_child(inode); ++ ++ err = flush(file, id); ++ au_cpup_attr_timesizes(inode); ++ ++ ii_read_unlock(inode); ++ fi_read_unlock(file); ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_file_refresh_by_inode(struct file *file, int *need_reopen) ++{ ++ int err; ++ struct au_pin pin; ++ struct au_finfo *finfo; ++ struct dentry *parent, *hi_wh; ++ struct inode *inode; ++ struct super_block *sb; ++ struct au_cp_generic cpg = { ++ .dentry = file->f_path.dentry, ++ .bdst = -1, ++ .bsrc = -1, ++ .len = -1, ++ .pin = &pin, ++ .flags = AuCpup_DTIME ++ }; ++ ++ FiMustWriteLock(file); ++ ++ err = 0; ++ finfo = au_fi(file); ++ sb = cpg.dentry->d_sb; ++ inode = d_inode(cpg.dentry); ++ cpg.bdst = au_ibtop(inode); ++ if (cpg.bdst == finfo->fi_btop || IS_ROOT(cpg.dentry)) ++ goto out; ++ ++ parent = dget_parent(cpg.dentry); ++ if (au_test_ro(sb, cpg.bdst, inode)) { ++ di_read_lock_parent(parent, !AuLock_IR); ++ err = AuWbrCopyup(au_sbi(sb), cpg.dentry); ++ cpg.bdst = err; ++ di_read_unlock(parent, !AuLock_IR); ++ if (unlikely(err < 0)) ++ goto out_parent; ++ err = 0; ++ } ++ ++ di_read_lock_parent(parent, AuLock_IR); ++ hi_wh = au_hi_wh(inode, cpg.bdst); ++ if (!S_ISDIR(inode->i_mode) ++ && au_opt_test(au_mntflags(sb), PLINK) ++ && au_plink_test(inode) ++ && !d_unhashed(cpg.dentry) ++ && cpg.bdst < au_dbtop(cpg.dentry)) { ++ err = au_test_and_cpup_dirs(cpg.dentry, cpg.bdst); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ /* always superio. */ ++ err = au_pin(&pin, cpg.dentry, cpg.bdst, AuOpt_UDBA_NONE, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (!err) { ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&pin); ++ } ++ } else if (hi_wh) { ++ /* already copied-up after unlink */ ++ err = au_reopen_wh(file, cpg.bdst, hi_wh); ++ *need_reopen = 0; ++ } ++ ++out_unlock: ++ di_read_unlock(parent, AuLock_IR); ++out_parent: ++ dput(parent); ++out: ++ return err; ++} ++ ++static void au_do_refresh_dir(struct file *file) ++{ ++ aufs_bindex_t bindex, bbot, new_bindex, brid; ++ struct au_hfile *p, tmp, *q; ++ struct au_finfo *finfo; ++ struct super_block *sb; ++ struct au_fidir *fidir; ++ ++ FiMustWriteLock(file); ++ ++ sb = file->f_path.dentry->d_sb; ++ finfo = au_fi(file); ++ fidir = finfo->fi_hdir; ++ AuDebugOn(!fidir); ++ p = fidir->fd_hfile + finfo->fi_btop; ++ brid = p->hf_br->br_id; ++ bbot = fidir->fd_bbot; ++ for (bindex = finfo->fi_btop; bindex <= bbot; bindex++, p++) { ++ if (!p->hf_file) ++ continue; ++ ++ new_bindex = au_br_index(sb, p->hf_br->br_id); ++ if (new_bindex == bindex) ++ continue; ++ if (new_bindex < 0) { ++ au_set_h_fptr(file, bindex, NULL); ++ continue; ++ } ++ ++ /* swap two lower inode, and loop again */ ++ q = fidir->fd_hfile + new_bindex; ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hf_file) { ++ bindex--; ++ p--; ++ } ++ } ++ ++ p = fidir->fd_hfile; ++ if (!au_test_mmapped(file) && !d_unlinked(file->f_path.dentry)) { ++ bbot = au_sbbot(sb); ++ for (finfo->fi_btop = 0; finfo->fi_btop <= bbot; ++ finfo->fi_btop++, p++) ++ if (p->hf_file) { ++ if (file_inode(p->hf_file)) ++ break; ++ au_hfput(p, /*execed*/0); ++ } ++ } else { ++ bbot = au_br_index(sb, brid); ++ for (finfo->fi_btop = 0; finfo->fi_btop < bbot; ++ finfo->fi_btop++, p++) ++ if (p->hf_file) ++ au_hfput(p, /*execed*/0); ++ bbot = au_sbbot(sb); ++ } ++ ++ p = fidir->fd_hfile + bbot; ++ for (fidir->fd_bbot = bbot; fidir->fd_bbot >= finfo->fi_btop; ++ fidir->fd_bbot--, p--) ++ if (p->hf_file) { ++ if (file_inode(p->hf_file)) ++ break; ++ au_hfput(p, /*execed*/0); ++ } ++ AuDebugOn(fidir->fd_bbot < finfo->fi_btop); ++} ++ ++/* ++ * after branch manipulating, refresh the file. ++ */ ++static int refresh_file(struct file *file, int (*reopen)(struct file *file)) ++{ ++ int err, need_reopen, nbr; ++ aufs_bindex_t bbot, bindex; ++ struct dentry *dentry; ++ struct super_block *sb; ++ struct au_finfo *finfo; ++ struct au_hfile *hfile; ++ ++ dentry = file->f_path.dentry; ++ sb = dentry->d_sb; ++ nbr = au_sbbot(sb) + 1; ++ finfo = au_fi(file); ++ if (!finfo->fi_hdir) { ++ hfile = &finfo->fi_htop; ++ AuDebugOn(!hfile->hf_file); ++ bindex = au_br_index(sb, hfile->hf_br->br_id); ++ AuDebugOn(bindex < 0); ++ if (bindex != finfo->fi_btop) ++ au_set_fbtop(file, bindex); ++ } else { ++ err = au_fidir_realloc(finfo, nbr, /*may_shrink*/0); ++ if (unlikely(err)) ++ goto out; ++ au_do_refresh_dir(file); ++ } ++ ++ err = 0; ++ need_reopen = 1; ++ if (!au_test_mmapped(file)) ++ err = au_file_refresh_by_inode(file, &need_reopen); ++ if (finfo->fi_hdir) ++ /* harmless if err */ ++ au_fidir_realloc(finfo, nbr, /*may_shrink*/1); ++ if (!err && need_reopen && !d_unlinked(dentry)) ++ err = reopen(file); ++ if (!err) { ++ au_update_figen(file); ++ goto out; /* success */ ++ } ++ ++ /* error, close all lower files */ ++ if (finfo->fi_hdir) { ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); bindex <= bbot; bindex++) ++ au_set_h_fptr(file, bindex, NULL); ++ } ++ ++out: ++ return err; ++} ++ ++/* common function to regular file and dir */ ++int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file), ++ int wlock, unsigned int fi_lsc) ++{ ++ int err; ++ unsigned int sigen, figen; ++ aufs_bindex_t btop; ++ unsigned char pseudo_link; ++ struct dentry *dentry; ++ struct inode *inode; ++ ++ err = 0; ++ dentry = file->f_path.dentry; ++ inode = d_inode(dentry); ++ sigen = au_sigen(dentry->d_sb); ++ fi_write_lock_nested(file, fi_lsc); ++ figen = au_figen(file); ++ if (!fi_lsc) ++ di_write_lock_child(dentry); ++ else ++ di_write_lock_child2(dentry); ++ btop = au_dbtop(dentry); ++ pseudo_link = (btop != au_ibtop(inode)); ++ if (sigen == figen && !pseudo_link && au_fbtop(file) == btop) { ++ if (!wlock) { ++ di_downgrade_lock(dentry, AuLock_IR); ++ fi_downgrade_lock(file); ++ } ++ goto out; /* success */ ++ } ++ ++ AuDbg("sigen %d, figen %d\n", sigen, figen); ++ if (au_digen_test(dentry, sigen)) { ++ err = au_reval_dpath(dentry, sigen); ++ AuDebugOn(!err && au_digen_test(dentry, sigen)); ++ } ++ ++ if (!err) ++ err = refresh_file(file, reopen); ++ if (!err) { ++ if (!wlock) { ++ di_downgrade_lock(dentry, AuLock_IR); ++ fi_downgrade_lock(file); ++ } ++ } else { ++ di_write_unlock(dentry); ++ fi_write_unlock(file); ++ } ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* cf. aufs_nopage() */ ++/* for madvise(2) */ ++static int aufs_readpage(struct file *file __maybe_unused, struct page *page) ++{ ++ unlock_page(page); ++ return 0; ++} ++ ++/* it will never be called, but necessary to support O_DIRECT */ ++static ssize_t aufs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) ++{ BUG(); return 0; } ++ ++/* they will never be called. */ ++#ifdef CONFIG_AUFS_DEBUG ++static int aufs_write_begin(struct file *file, struct address_space *mapping, ++ loff_t pos, unsigned len, unsigned flags, ++ struct page **pagep, void **fsdata) ++{ AuUnsupport(); return 0; } ++static int aufs_write_end(struct file *file, struct address_space *mapping, ++ loff_t pos, unsigned len, unsigned copied, ++ struct page *page, void *fsdata) ++{ AuUnsupport(); return 0; } ++static int aufs_writepage(struct page *page, struct writeback_control *wbc) ++{ AuUnsupport(); return 0; } ++ ++static int aufs_set_page_dirty(struct page *page) ++{ AuUnsupport(); return 0; } ++static void aufs_invalidatepage(struct page *page, unsigned int offset, ++ unsigned int length) ++{ AuUnsupport(); } ++static int aufs_releasepage(struct page *page, gfp_t gfp) ++{ AuUnsupport(); return 0; } ++#if 0 /* called by memory compaction regardless file */ ++static int aufs_migratepage(struct address_space *mapping, struct page *newpage, ++ struct page *page, enum migrate_mode mode) ++{ AuUnsupport(); return 0; } ++#endif ++static bool aufs_isolate_page(struct page *page, isolate_mode_t mode) ++{ AuUnsupport(); return true; } ++static void aufs_putback_page(struct page *page) ++{ AuUnsupport(); } ++static int aufs_launder_page(struct page *page) ++{ AuUnsupport(); return 0; } ++static int aufs_is_partially_uptodate(struct page *page, ++ unsigned long from, ++ unsigned long count) ++{ AuUnsupport(); return 0; } ++static void aufs_is_dirty_writeback(struct page *page, bool *dirty, ++ bool *writeback) ++{ AuUnsupport(); } ++static int aufs_error_remove_page(struct address_space *mapping, ++ struct page *page) ++{ AuUnsupport(); return 0; } ++static int aufs_swap_activate(struct swap_info_struct *sis, struct file *file, ++ sector_t *span) ++{ AuUnsupport(); return 0; } ++static void aufs_swap_deactivate(struct file *file) ++{ AuUnsupport(); } ++#endif /* CONFIG_AUFS_DEBUG */ ++ ++const struct address_space_operations aufs_aop = { ++ .readpage = aufs_readpage, ++ .direct_IO = aufs_direct_IO, ++#ifdef CONFIG_AUFS_DEBUG ++ .writepage = aufs_writepage, ++ /* no writepages, because of writepage */ ++ .set_page_dirty = aufs_set_page_dirty, ++ /* no readpages, because of readpage */ ++ .write_begin = aufs_write_begin, ++ .write_end = aufs_write_end, ++ /* no bmap, no block device */ ++ .invalidatepage = aufs_invalidatepage, ++ .releasepage = aufs_releasepage, ++ /* is fallback_migrate_page ok? */ ++ /* .migratepage = aufs_migratepage, */ ++ .isolate_page = aufs_isolate_page, ++ .putback_page = aufs_putback_page, ++ .launder_page = aufs_launder_page, ++ .is_partially_uptodate = aufs_is_partially_uptodate, ++ .is_dirty_writeback = aufs_is_dirty_writeback, ++ .error_remove_page = aufs_error_remove_page, ++ .swap_activate = aufs_swap_activate, ++ .swap_deactivate = aufs_swap_deactivate ++#endif /* CONFIG_AUFS_DEBUG */ ++}; +diff -Nurp linux-5.15.37/fs/aufs/file.h linux-5.15.37-aufs/fs/aufs/file.h +--- linux-5.15.37/fs/aufs/file.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/file.h 2022-04-08 20:22:30.613616524 +0300 +@@ -0,0 +1,329 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * file operations ++ */ ++ ++#ifndef __AUFS_FILE_H__ ++#define __AUFS_FILE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++#include "rwsem.h" ++ ++struct au_branch; ++struct au_hfile { ++ struct file *hf_file; ++ struct au_branch *hf_br; ++}; ++ ++struct au_vdir; ++struct au_fidir { ++ aufs_bindex_t fd_bbot; ++ aufs_bindex_t fd_nent; ++ struct au_vdir *fd_vdir_cache; ++ struct au_hfile fd_hfile[]; ++}; ++ ++static inline int au_fidir_sz(int nent) ++{ ++ AuDebugOn(nent < 0); ++ return sizeof(struct au_fidir) + sizeof(struct au_hfile) * nent; ++} ++ ++struct au_finfo { ++ atomic_t fi_generation; ++ ++ struct au_rwsem fi_rwsem; ++ aufs_bindex_t fi_btop; ++ ++ /* do not union them */ ++ struct { /* for non-dir */ ++ struct au_hfile fi_htop; ++ atomic_t fi_mmapped; ++ }; ++ struct au_fidir *fi_hdir; /* for dir only */ ++ ++ struct hlist_bl_node fi_hlist; ++ struct file *fi_file; /* very ugly */ ++ struct rcu_head rcu; ++} ____cacheline_aligned_in_smp; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* file.c */ ++extern const struct address_space_operations aufs_aop; ++unsigned int au_file_roflags(unsigned int flags); ++struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, ++ struct file *file, int force_wr); ++struct au_do_open_args { ++ int aopen; ++ int (*open)(struct file *file, int flags, ++ struct file *h_file); ++ struct au_fidir *fidir; ++ struct file *h_file; ++}; ++int au_do_open(struct file *file, struct au_do_open_args *args); ++int au_reopen_nondir(struct file *file); ++struct au_pin; ++int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin); ++int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file), ++ int wlock, unsigned int fi_lsc); ++int au_do_flush(struct file *file, fl_owner_t id, ++ int (*flush)(struct file *file, fl_owner_t id)); ++ ++/* poll.c */ ++#ifdef CONFIG_AUFS_POLL ++__poll_t aufs_poll(struct file *file, struct poll_table_struct *pt); ++#endif ++ ++#ifdef CONFIG_AUFS_BR_HFSPLUS ++/* hfsplus.c */ ++struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex, ++ int force_wr); ++void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex, ++ struct file *h_file); ++#else ++AuStub(struct file *, au_h_open_pre, return NULL, struct dentry *dentry, ++ aufs_bindex_t bindex, int force_wr) ++AuStubVoid(au_h_open_post, struct dentry *dentry, aufs_bindex_t bindex, ++ struct file *h_file); ++#endif ++ ++/* f_op.c */ ++extern const struct file_operations aufs_file_fop; ++int au_do_open_nondir(struct file *file, int flags, struct file *h_file); ++int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file); ++struct file *au_read_pre(struct file *file, int keep_fi, unsigned int lsc); ++ ++/* finfo.c */ ++void au_hfput(struct au_hfile *hf, int execed); ++void au_set_h_fptr(struct file *file, aufs_bindex_t bindex, ++ struct file *h_file); ++ ++void au_update_figen(struct file *file); ++struct au_fidir *au_fidir_alloc(struct super_block *sb); ++int au_fidir_realloc(struct au_finfo *finfo, int nbr, int may_shrink); ++ ++void au_fi_init_once(void *_fi); ++void au_finfo_fin(struct file *file); ++int au_finfo_init(struct file *file, struct au_fidir *fidir); ++ ++/* ioctl.c */ ++long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg); ++#ifdef CONFIG_COMPAT ++long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd, ++ unsigned long arg); ++long aufs_compat_ioctl_nondir(struct file *file, unsigned int cmd, ++ unsigned long arg); ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_finfo *au_fi(struct file *file) ++{ ++ return file->private_data; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define fi_read_lock(f) au_rw_read_lock(&au_fi(f)->fi_rwsem) ++#define fi_write_lock(f) au_rw_write_lock(&au_fi(f)->fi_rwsem) ++#define fi_read_trylock(f) au_rw_read_trylock(&au_fi(f)->fi_rwsem) ++#define fi_write_trylock(f) au_rw_write_trylock(&au_fi(f)->fi_rwsem) ++/* ++#define fi_read_trylock_nested(f) \ ++ au_rw_read_trylock_nested(&au_fi(f)->fi_rwsem) ++#define fi_write_trylock_nested(f) \ ++ au_rw_write_trylock_nested(&au_fi(f)->fi_rwsem) ++*/ ++ ++#define fi_read_unlock(f) au_rw_read_unlock(&au_fi(f)->fi_rwsem) ++#define fi_write_unlock(f) au_rw_write_unlock(&au_fi(f)->fi_rwsem) ++#define fi_downgrade_lock(f) au_rw_dgrade_lock(&au_fi(f)->fi_rwsem) ++ ++/* lock subclass for finfo */ ++enum { ++ AuLsc_FI_1, ++ AuLsc_FI_2 ++}; ++ ++static inline void fi_read_lock_nested(struct file *f, unsigned int lsc) ++{ ++ au_rw_read_lock_nested(&au_fi(f)->fi_rwsem, lsc); ++} ++ ++static inline void fi_write_lock_nested(struct file *f, unsigned int lsc) ++{ ++ au_rw_write_lock_nested(&au_fi(f)->fi_rwsem, lsc); ++} ++ ++/* ++ * fi_read_lock_1, fi_write_lock_1, ++ * fi_read_lock_2, fi_write_lock_2 ++ */ ++#define AuReadLockFunc(name) \ ++static inline void fi_read_lock_##name(struct file *f) \ ++{ fi_read_lock_nested(f, AuLsc_FI_##name); } ++ ++#define AuWriteLockFunc(name) \ ++static inline void fi_write_lock_##name(struct file *f) \ ++{ fi_write_lock_nested(f, AuLsc_FI_##name); } ++ ++#define AuRWLockFuncs(name) \ ++ AuReadLockFunc(name) \ ++ AuWriteLockFunc(name) ++ ++AuRWLockFuncs(1); ++AuRWLockFuncs(2); ++ ++#undef AuReadLockFunc ++#undef AuWriteLockFunc ++#undef AuRWLockFuncs ++ ++#define FiMustNoWaiters(f) AuRwMustNoWaiters(&au_fi(f)->fi_rwsem) ++#define FiMustAnyLock(f) AuRwMustAnyLock(&au_fi(f)->fi_rwsem) ++#define FiMustWriteLock(f) AuRwMustWriteLock(&au_fi(f)->fi_rwsem) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* todo: hard/soft set? */ ++static inline aufs_bindex_t au_fbtop(struct file *file) ++{ ++ FiMustAnyLock(file); ++ return au_fi(file)->fi_btop; ++} ++ ++static inline aufs_bindex_t au_fbbot_dir(struct file *file) ++{ ++ FiMustAnyLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ return au_fi(file)->fi_hdir->fd_bbot; ++} ++ ++static inline struct au_vdir *au_fvdir_cache(struct file *file) ++{ ++ FiMustAnyLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ return au_fi(file)->fi_hdir->fd_vdir_cache; ++} ++ ++static inline void au_set_fbtop(struct file *file, aufs_bindex_t bindex) ++{ ++ FiMustWriteLock(file); ++ au_fi(file)->fi_btop = bindex; ++} ++ ++static inline void au_set_fbbot_dir(struct file *file, aufs_bindex_t bindex) ++{ ++ FiMustWriteLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ au_fi(file)->fi_hdir->fd_bbot = bindex; ++} ++ ++static inline void au_set_fvdir_cache(struct file *file, ++ struct au_vdir *vdir_cache) ++{ ++ FiMustWriteLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ au_fi(file)->fi_hdir->fd_vdir_cache = vdir_cache; ++} ++ ++static inline struct file *au_hf_top(struct file *file) ++{ ++ FiMustAnyLock(file); ++ AuDebugOn(au_fi(file)->fi_hdir); ++ return au_fi(file)->fi_htop.hf_file; ++} ++ ++static inline struct file *au_hf_dir(struct file *file, aufs_bindex_t bindex) ++{ ++ FiMustAnyLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ return au_fi(file)->fi_hdir->fd_hfile[0 + bindex].hf_file; ++} ++ ++/* todo: memory barrier? */ ++static inline unsigned int au_figen(struct file *f) ++{ ++ return atomic_read(&au_fi(f)->fi_generation); ++} ++ ++static inline void au_set_mmapped(struct file *f) ++{ ++ if (atomic_inc_return(&au_fi(f)->fi_mmapped)) ++ return; ++ pr_warn("fi_mmapped wrapped around\n"); ++ while (!atomic_inc_return(&au_fi(f)->fi_mmapped)) ++ ; ++} ++ ++static inline void au_unset_mmapped(struct file *f) ++{ ++ atomic_dec(&au_fi(f)->fi_mmapped); ++} ++ ++static inline int au_test_mmapped(struct file *f) ++{ ++ return atomic_read(&au_fi(f)->fi_mmapped); ++} ++ ++/* customize vma->vm_file */ ++ ++static inline void au_do_vm_file_reset(struct vm_area_struct *vma, ++ struct file *file) ++{ ++ struct file *f; ++ ++ f = vma->vm_file; ++ get_file(file); ++ vma->vm_file = file; ++ fput(f); ++} ++ ++#ifdef CONFIG_MMU ++#define AuDbgVmRegion(file, vma) do {} while (0) ++ ++static inline void au_vm_file_reset(struct vm_area_struct *vma, ++ struct file *file) ++{ ++ au_do_vm_file_reset(vma, file); ++} ++#else ++#define AuDbgVmRegion(file, vma) \ ++ AuDebugOn((vma)->vm_region && (vma)->vm_region->vm_file != (file)) ++ ++static inline void au_vm_file_reset(struct vm_area_struct *vma, ++ struct file *file) ++{ ++ struct file *f; ++ ++ au_do_vm_file_reset(vma, file); ++ f = vma->vm_region->vm_file; ++ get_file(file); ++ vma->vm_region->vm_file = file; ++ fput(f); ++} ++#endif /* CONFIG_MMU */ ++ ++/* handle vma->vm_prfile */ ++static inline void au_vm_prfile_set(struct vm_area_struct *vma, ++ struct file *file) ++{ ++ get_file(file); ++ vma->vm_prfile = file; ++#ifndef CONFIG_MMU ++ get_file(file); ++ vma->vm_region->vm_prfile = file; ++#endif ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_FILE_H__ */ +diff -Nurp linux-5.15.37/fs/aufs/finfo.c linux-5.15.37-aufs/fs/aufs/finfo.c +--- linux-5.15.37/fs/aufs/finfo.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/finfo.c 2022-04-08 20:22:30.613616524 +0300 +@@ -0,0 +1,136 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * file private data ++ */ ++ ++#include "aufs.h" ++ ++void au_hfput(struct au_hfile *hf, int execed) ++{ ++ if (execed) ++ allow_write_access(hf->hf_file); ++ fput(hf->hf_file); ++ hf->hf_file = NULL; ++ au_lcnt_dec(&hf->hf_br->br_nfiles); ++ hf->hf_br = NULL; ++} ++ ++void au_set_h_fptr(struct file *file, aufs_bindex_t bindex, struct file *val) ++{ ++ struct au_finfo *finfo = au_fi(file); ++ struct au_hfile *hf; ++ struct au_fidir *fidir; ++ ++ fidir = finfo->fi_hdir; ++ if (!fidir) { ++ AuDebugOn(finfo->fi_btop != bindex); ++ hf = &finfo->fi_htop; ++ } else ++ hf = fidir->fd_hfile + bindex; ++ ++ if (hf && hf->hf_file) ++ au_hfput(hf, vfsub_file_execed(file)); ++ if (val) { ++ FiMustWriteLock(file); ++ AuDebugOn(IS_ERR_OR_NULL(file->f_path.dentry)); ++ hf->hf_file = val; ++ hf->hf_br = au_sbr(file->f_path.dentry->d_sb, bindex); ++ } ++} ++ ++void au_update_figen(struct file *file) ++{ ++ atomic_set(&au_fi(file)->fi_generation, au_digen(file->f_path.dentry)); ++ /* smp_mb(); */ /* atomic_set */ ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_fidir *au_fidir_alloc(struct super_block *sb) ++{ ++ struct au_fidir *fidir; ++ int nbr; ++ ++ nbr = au_sbbot(sb) + 1; ++ if (nbr < 2) ++ nbr = 2; /* initial allocate for 2 branches */ ++ fidir = kzalloc(au_fidir_sz(nbr), GFP_NOFS); ++ if (fidir) { ++ fidir->fd_bbot = -1; ++ fidir->fd_nent = nbr; ++ } ++ ++ return fidir; ++} ++ ++int au_fidir_realloc(struct au_finfo *finfo, int nbr, int may_shrink) ++{ ++ int err; ++ struct au_fidir *fidir, *p; ++ ++ AuRwMustWriteLock(&finfo->fi_rwsem); ++ fidir = finfo->fi_hdir; ++ AuDebugOn(!fidir); ++ ++ err = -ENOMEM; ++ p = au_kzrealloc(fidir, au_fidir_sz(fidir->fd_nent), au_fidir_sz(nbr), ++ GFP_NOFS, may_shrink); ++ if (p) { ++ p->fd_nent = nbr; ++ finfo->fi_hdir = p; ++ err = 0; ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_finfo_fin(struct file *file) ++{ ++ struct au_finfo *finfo; ++ ++ au_lcnt_dec(&au_sbi(file->f_path.dentry->d_sb)->si_nfiles); ++ ++ finfo = au_fi(file); ++ AuDebugOn(finfo->fi_hdir); ++ AuRwDestroy(&finfo->fi_rwsem); ++ au_cache_free_finfo(finfo); ++} ++ ++void au_fi_init_once(void *_finfo) ++{ ++ struct au_finfo *finfo = _finfo; ++ ++ au_rw_init(&finfo->fi_rwsem); ++} ++ ++int au_finfo_init(struct file *file, struct au_fidir *fidir) ++{ ++ int err; ++ struct au_finfo *finfo; ++ struct dentry *dentry; ++ ++ err = -ENOMEM; ++ dentry = file->f_path.dentry; ++ finfo = au_cache_alloc_finfo(); ++ if (unlikely(!finfo)) ++ goto out; ++ ++ err = 0; ++ au_lcnt_inc(&au_sbi(dentry->d_sb)->si_nfiles); ++ au_rw_write_lock(&finfo->fi_rwsem); ++ finfo->fi_btop = -1; ++ finfo->fi_hdir = fidir; ++ atomic_set(&finfo->fi_generation, au_digen(dentry)); ++ /* smp_mb(); */ /* atomic_set */ ++ ++ file->private_data = finfo; ++ ++out: ++ return err; ++} +diff -Nurp linux-5.15.37/fs/aufs/f_op.c linux-5.15.37-aufs/fs/aufs/f_op.c +--- linux-5.15.37/fs/aufs/f_op.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/f_op.c 2022-04-08 20:22:30.612616475 +0300 +@@ -0,0 +1,758 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * file and vm operations ++ */ ++ ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++int au_do_open_nondir(struct file *file, int flags, struct file *h_file) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct dentry *dentry, *h_dentry; ++ struct au_finfo *finfo; ++ struct inode *h_inode; ++ ++ FiMustWriteLock(file); ++ ++ err = 0; ++ dentry = file->f_path.dentry; ++ AuDebugOn(IS_ERR_OR_NULL(dentry)); ++ finfo = au_fi(file); ++ memset(&finfo->fi_htop, 0, sizeof(finfo->fi_htop)); ++ atomic_set(&finfo->fi_mmapped, 0); ++ bindex = au_dbtop(dentry); ++ if (!h_file) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ err = vfsub_test_mntns(file->f_path.mnt, h_dentry->d_sb); ++ if (unlikely(err)) ++ goto out; ++ h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0); ++ if (IS_ERR(h_file)) { ++ err = PTR_ERR(h_file); ++ goto out; ++ } ++ } else { ++ h_dentry = h_file->f_path.dentry; ++ err = vfsub_test_mntns(file->f_path.mnt, h_dentry->d_sb); ++ if (unlikely(err)) ++ goto out; ++ /* br ref is already inc-ed */ ++ } ++ ++ if ((flags & __O_TMPFILE) ++ && !(flags & O_EXCL)) { ++ h_inode = file_inode(h_file); ++ spin_lock(&h_inode->i_lock); ++ h_inode->i_state |= I_LINKABLE; ++ spin_unlock(&h_inode->i_lock); ++ } ++ au_set_fbtop(file, bindex); ++ au_set_h_fptr(file, bindex, h_file); ++ au_update_figen(file); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ ++out: ++ return err; ++} ++ ++static int aufs_open_nondir(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ int err; ++ struct super_block *sb; ++ struct au_do_open_args args = { ++ .open = au_do_open_nondir ++ }; ++ ++ AuDbg("%pD, f_flags 0x%x, f_mode 0x%x\n", ++ file, vfsub_file_flags(file), file->f_mode); ++ ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ err = au_do_open(file, &args); ++ si_read_unlock(sb); ++ return err; ++} ++ ++int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file) ++{ ++ struct au_finfo *finfo; ++ aufs_bindex_t bindex; ++ ++ finfo = au_fi(file); ++ au_hbl_del(&finfo->fi_hlist, ++ &au_sbi(file->f_path.dentry->d_sb)->si_files); ++ bindex = finfo->fi_btop; ++ if (bindex >= 0) ++ au_set_h_fptr(file, bindex, NULL); ++ ++ au_finfo_fin(file); ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_flush_nondir(struct file *file, fl_owner_t id) ++{ ++ int err; ++ struct file *h_file; ++ ++ err = 0; ++ h_file = au_hf_top(file); ++ if (h_file) ++ err = vfsub_flush(h_file, id); ++ return err; ++} ++ ++static int aufs_flush_nondir(struct file *file, fl_owner_t id) ++{ ++ return au_do_flush(file, id, au_do_flush_nondir); ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * read and write functions acquire [fdi]_rwsem once, but release before ++ * mmap_sem. This is because to stop a race condition between mmap(2). ++ * Releasing these aufs-rwsem should be safe, no branch-management (by keeping ++ * si_rwsem), no harmful copy-up should happen. Actually copy-up may happen in ++ * read functions after [fdi]_rwsem are released, but it should be harmless. ++ */ ++ ++/* Callers should call au_read_post() or fput() in the end */ ++struct file *au_read_pre(struct file *file, int keep_fi, unsigned int lsc) ++{ ++ struct file *h_file; ++ int err; ++ ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0, lsc); ++ if (!err) { ++ di_read_unlock(file->f_path.dentry, AuLock_IR); ++ h_file = au_hf_top(file); ++ get_file(h_file); ++ if (!keep_fi) ++ fi_read_unlock(file); ++ } else ++ h_file = ERR_PTR(err); ++ ++ return h_file; ++} ++ ++static void au_read_post(struct inode *inode, struct file *h_file) ++{ ++ /* update without lock, I don't think it a problem */ ++ fsstack_copy_attr_atime(inode, file_inode(h_file)); ++ fput(h_file); ++} ++ ++struct au_write_pre { ++ /* input */ ++ unsigned int lsc; ++ ++ /* output */ ++ blkcnt_t blks; ++ aufs_bindex_t btop; ++}; ++ ++/* ++ * return with iinfo is write-locked ++ * callers should call au_write_post() or iinfo_write_unlock() + fput() in the ++ * end ++ */ ++static struct file *au_write_pre(struct file *file, int do_ready, ++ struct au_write_pre *wpre) ++{ ++ struct file *h_file; ++ struct dentry *dentry; ++ int err; ++ unsigned int lsc; ++ struct au_pin pin; ++ ++ lsc = 0; ++ if (wpre) ++ lsc = wpre->lsc; ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1, lsc); ++ h_file = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ dentry = file->f_path.dentry; ++ if (do_ready) { ++ err = au_ready_to_write(file, -1, &pin); ++ if (unlikely(err)) { ++ h_file = ERR_PTR(err); ++ di_write_unlock(dentry); ++ goto out_fi; ++ } ++ } ++ ++ di_downgrade_lock(dentry, /*flags*/0); ++ if (wpre) ++ wpre->btop = au_fbtop(file); ++ h_file = au_hf_top(file); ++ get_file(h_file); ++ if (wpre) ++ wpre->blks = file_inode(h_file)->i_blocks; ++ if (do_ready) ++ au_unpin(&pin); ++ di_read_unlock(dentry, /*flags*/0); ++ ++out_fi: ++ fi_write_unlock(file); ++out: ++ return h_file; ++} ++ ++static void au_write_post(struct inode *inode, struct file *h_file, ++ struct au_write_pre *wpre, ssize_t written) ++{ ++ struct inode *h_inode; ++ ++ au_cpup_attr_timesizes(inode); ++ AuDebugOn(au_ibtop(inode) != wpre->btop); ++ h_inode = file_inode(h_file); ++ inode->i_mode = h_inode->i_mode; ++ ii_write_unlock(inode); ++ /* AuDbg("blks %llu, %llu\n", (u64)blks, (u64)h_inode->i_blocks); */ ++ if (written > 0) ++ au_fhsm_wrote(inode->i_sb, wpre->btop, ++ /*force*/h_inode->i_blocks > wpre->blks); ++ fput(h_file); ++} ++ ++/* ++ * todo: very ugly ++ * it locks both of i_mutex and si_rwsem for read in safe. ++ * if the plink maintenance mode continues forever (that is the problem), ++ * may loop forever. ++ */ ++static void au_mtx_and_read_lock(struct inode *inode) ++{ ++ int err; ++ struct super_block *sb = inode->i_sb; ++ ++ while (1) { ++ inode_lock(inode); ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (!err) ++ break; ++ inode_unlock(inode); ++ si_read_lock(sb, AuLock_NOPLMW); ++ si_read_unlock(sb); ++ } ++} ++ ++static ssize_t au_do_iter(struct file *h_file, int rw, struct kiocb *kio, ++ struct iov_iter *iov_iter) ++{ ++ ssize_t err; ++ struct file *file; ++ ssize_t (*iter)(struct kiocb *, struct iov_iter *); ++ ++ err = security_file_permission(h_file, rw); ++ if (unlikely(err)) ++ goto out; ++ ++ err = -ENOSYS; /* the branch doesn't have its ->(read|write)_iter() */ ++ iter = NULL; ++ if (rw == MAY_READ) ++ iter = h_file->f_op->read_iter; ++ else if (rw == MAY_WRITE) ++ iter = h_file->f_op->write_iter; ++ ++ file = kio->ki_filp; ++ kio->ki_filp = h_file; ++ if (iter) { ++ lockdep_off(); ++ err = iter(kio, iov_iter); ++ lockdep_on(); ++ } else ++ /* currently there is no such fs */ ++ WARN_ON_ONCE(1); ++ kio->ki_filp = file; ++ ++out: ++ return err; ++} ++ ++static ssize_t aufs_read_iter(struct kiocb *kio, struct iov_iter *iov_iter) ++{ ++ ssize_t err; ++ struct file *file, *h_file; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ file = kio->ki_filp; ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/1, /*lsc*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ if (au_test_loopback_kthread()) { ++ au_warn_loopback(h_file->f_path.dentry->d_sb); ++ if (file->f_mapping != h_file->f_mapping) { ++ file->f_mapping = h_file->f_mapping; ++ smp_mb(); /* unnecessary? */ ++ } ++ } ++ fi_read_unlock(file); ++ ++ err = au_do_iter(h_file, MAY_READ, kio, iov_iter); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ au_read_post(inode, h_file); ++ ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++static ssize_t aufs_write_iter(struct kiocb *kio, struct iov_iter *iov_iter) ++{ ++ ssize_t err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *file, *h_file; ++ ++ file = kio->ki_filp; ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ wpre.lsc = 0; ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = au_do_iter(h_file, MAY_WRITE, kio, iov_iter); ++ au_write_post(inode, h_file, &wpre, err); ++ ++out: ++ si_read_unlock(inode->i_sb); ++ inode_unlock(inode); ++ return err; ++} ++ ++/* ++ * We may be able to remove aufs_splice_{read,write}() since almost all FSes ++ * don't have their own .splice_{read,write} implimentations, and they use ++ * generic_file_splice_read() and iter_file_splice_write() who can act like the ++ * simple converters to f_op->iter_read() and ->iter_write(). ++ * But we keep our own implementations because some non-mainlined FSes may have ++ * their own .splice_{read,write} implimentations and aufs doesn't want to take ++ * away an opportunity to co-work with aufs from them. ++ */ ++static ssize_t aufs_splice_read(struct file *file, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags) ++{ ++ ssize_t err; ++ struct file *h_file; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/0, /*lsc*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = vfsub_splice_to(h_file, ppos, pipe, len, flags); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ au_read_post(inode, h_file); ++ ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++static ssize_t ++aufs_splice_write(struct pipe_inode_info *pipe, struct file *file, loff_t *ppos, ++ size_t len, unsigned int flags) ++{ ++ ssize_t err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *h_file; ++ ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ wpre.lsc = 0; ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = vfsub_splice_from(pipe, h_file, ppos, len, flags); ++ au_write_post(inode, h_file, &wpre, err); ++ ++out: ++ si_read_unlock(inode->i_sb); ++ inode_unlock(inode); ++ return err; ++} ++ ++static long aufs_fallocate(struct file *file, int mode, loff_t offset, ++ loff_t len) ++{ ++ long err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *h_file; ++ ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ wpre.lsc = 0; ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ lockdep_off(); ++ err = vfs_fallocate(h_file, mode, offset, len); ++ lockdep_on(); ++ au_write_post(inode, h_file, &wpre, /*written*/1); ++ ++out: ++ si_read_unlock(inode->i_sb); ++ inode_unlock(inode); ++ return err; ++} ++ ++static ssize_t aufs_copy_file_range(struct file *src, loff_t src_pos, ++ struct file *dst, loff_t dst_pos, ++ size_t len, unsigned int flags) ++{ ++ ssize_t err; ++ struct au_write_pre wpre; ++ enum { SRC, DST }; ++ struct { ++ struct inode *inode; ++ struct file *h_file; ++ struct super_block *h_sb; ++ } a[2]; ++#define a_src a[SRC] ++#define a_dst a[DST] ++ ++ err = -EINVAL; ++ a_src.inode = file_inode(src); ++ if (unlikely(!S_ISREG(a_src.inode->i_mode))) ++ goto out; ++ a_dst.inode = file_inode(dst); ++ if (unlikely(!S_ISREG(a_dst.inode->i_mode))) ++ goto out; ++ ++ au_mtx_and_read_lock(a_dst.inode); ++ /* ++ * in order to match the order in di_write_lock2_{child,parent}(), ++ * use f_path.dentry for this comparison. ++ */ ++ if (src->f_path.dentry < dst->f_path.dentry) { ++ a_src.h_file = au_read_pre(src, /*keep_fi*/1, AuLsc_FI_1); ++ err = PTR_ERR(a_src.h_file); ++ if (IS_ERR(a_src.h_file)) ++ goto out_si; ++ ++ wpre.lsc = AuLsc_FI_2; ++ a_dst.h_file = au_write_pre(dst, /*do_ready*/1, &wpre); ++ err = PTR_ERR(a_dst.h_file); ++ if (IS_ERR(a_dst.h_file)) { ++ au_read_post(a_src.inode, a_src.h_file); ++ goto out_si; ++ } ++ } else { ++ wpre.lsc = AuLsc_FI_1; ++ a_dst.h_file = au_write_pre(dst, /*do_ready*/1, &wpre); ++ err = PTR_ERR(a_dst.h_file); ++ if (IS_ERR(a_dst.h_file)) ++ goto out_si; ++ ++ a_src.h_file = au_read_pre(src, /*keep_fi*/1, AuLsc_FI_2); ++ err = PTR_ERR(a_src.h_file); ++ if (IS_ERR(a_src.h_file)) { ++ au_write_post(a_dst.inode, a_dst.h_file, &wpre, ++ /*written*/0); ++ goto out_si; ++ } ++ } ++ ++ err = -EXDEV; ++ a_src.h_sb = file_inode(a_src.h_file)->i_sb; ++ a_dst.h_sb = file_inode(a_dst.h_file)->i_sb; ++ if (unlikely(a_src.h_sb != a_dst.h_sb)) { ++ AuDbgFile(src); ++ AuDbgFile(dst); ++ goto out_file; ++ } ++ ++ err = vfsub_copy_file_range(a_src.h_file, src_pos, a_dst.h_file, ++ dst_pos, len, flags); ++ ++out_file: ++ au_write_post(a_dst.inode, a_dst.h_file, &wpre, err); ++ fi_read_unlock(src); ++ au_read_post(a_src.inode, a_src.h_file); ++out_si: ++ si_read_unlock(a_dst.inode->i_sb); ++ inode_unlock(a_dst.inode); ++out: ++ return err; ++#undef a_src ++#undef a_dst ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * The locking order around current->mmap_sem. ++ * - in most and regular cases ++ * file I/O syscall -- aufs_read() or something ++ * -- si_rwsem for read -- mmap_sem ++ * (Note that [fdi]i_rwsem are released before mmap_sem). ++ * - in mmap case ++ * mmap(2) -- mmap_sem -- aufs_mmap() -- si_rwsem for read -- [fdi]i_rwsem ++ * This AB-BA order is definitely bad, but is not a problem since "si_rwsem for ++ * read" allows multiple processes to acquire it and [fdi]i_rwsem are not held ++ * in file I/O. Aufs needs to stop lockdep in aufs_mmap() though. ++ * It means that when aufs acquires si_rwsem for write, the process should never ++ * acquire mmap_sem. ++ * ++ * Actually aufs_iterate() holds [fdi]i_rwsem before mmap_sem, but this is not a ++ * problem either since any directory is not able to be mmap-ed. ++ * The similar scenario is applied to aufs_readlink() too. ++ */ ++ ++#if 0 /* stop calling security_file_mmap() */ ++/* cf. linux/include/linux/mman.h: calc_vm_prot_bits() */ ++#define AuConv_VM_PROT(f, b) _calc_vm_trans(f, VM_##b, PROT_##b) ++ ++static unsigned long au_arch_prot_conv(unsigned long flags) ++{ ++ /* currently ppc64 only */ ++#ifdef CONFIG_PPC64 ++ /* cf. linux/arch/powerpc/include/asm/mman.h */ ++ AuDebugOn(arch_calc_vm_prot_bits(-1) != VM_SAO); ++ return AuConv_VM_PROT(flags, SAO); ++#else ++ AuDebugOn(arch_calc_vm_prot_bits(-1)); ++ return 0; ++#endif ++} ++ ++static unsigned long au_prot_conv(unsigned long flags) ++{ ++ return AuConv_VM_PROT(flags, READ) ++ | AuConv_VM_PROT(flags, WRITE) ++ | AuConv_VM_PROT(flags, EXEC) ++ | au_arch_prot_conv(flags); ++} ++ ++/* cf. linux/include/linux/mman.h: calc_vm_flag_bits() */ ++#define AuConv_VM_MAP(f, b) _calc_vm_trans(f, VM_##b, MAP_##b) ++ ++static unsigned long au_flag_conv(unsigned long flags) ++{ ++ return AuConv_VM_MAP(flags, GROWSDOWN) ++ | AuConv_VM_MAP(flags, DENYWRITE) ++ | AuConv_VM_MAP(flags, LOCKED); ++} ++#endif ++ ++static int aufs_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ int err; ++ const unsigned char wlock ++ = (file->f_mode & FMODE_WRITE) && (vma->vm_flags & VM_SHARED); ++ struct super_block *sb; ++ struct file *h_file; ++ struct inode *inode; ++ ++ AuDbgVmRegion(file, vma); ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ lockdep_off(); ++ si_read_lock(sb, AuLock_NOPLMW); ++ ++ h_file = au_write_pre(file, wlock, /*wpre*/NULL); ++ lockdep_on(); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = 0; ++ au_set_mmapped(file); ++ au_vm_file_reset(vma, h_file); ++ /* ++ * we cannot call security_mmap_file() here since it may acquire ++ * mmap_sem or i_mutex. ++ * ++ * err = security_mmap_file(h_file, au_prot_conv(vma->vm_flags), ++ * au_flag_conv(vma->vm_flags)); ++ */ ++ if (!err) ++ err = call_mmap(h_file, vma); ++ if (!err) { ++ au_vm_prfile_set(vma, file); ++ fsstack_copy_attr_atime(inode, file_inode(h_file)); ++ goto out_fput; /* success */ ++ } ++ au_unset_mmapped(file); ++ au_vm_file_reset(vma, file); ++ ++out_fput: ++ lockdep_off(); ++ ii_write_unlock(inode); ++ lockdep_on(); ++ fput(h_file); ++out: ++ lockdep_off(); ++ si_read_unlock(sb); ++ lockdep_on(); ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_fsync_nondir(struct file *file, loff_t start, loff_t end, ++ int datasync) ++{ ++ int err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *h_file; ++ ++ err = 0; /* -EBADF; */ /* posix? */ ++ if (unlikely(!(file->f_mode & FMODE_WRITE))) ++ goto out; ++ ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ wpre.lsc = 0; ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out_unlock; ++ ++ err = vfsub_fsync(h_file, &h_file->f_path, datasync); ++ au_write_post(inode, h_file, &wpre, /*written*/0); ++ ++out_unlock: ++ si_read_unlock(inode->i_sb); ++ inode_unlock(inode); ++out: ++ return err; ++} ++ ++static int aufs_fasync(int fd, struct file *file, int flag) ++{ ++ int err; ++ struct file *h_file; ++ struct super_block *sb; ++ ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/0, /*lsc*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ if (h_file->f_op->fasync) ++ err = h_file->f_op->fasync(fd, h_file, flag); ++ fput(h_file); /* instead of au_read_post() */ ++ ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++static int aufs_setfl(struct file *file, unsigned long arg) ++{ ++ int err; ++ struct file *h_file; ++ struct super_block *sb; ++ ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/0, /*lsc*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ /* stop calling h_file->fasync */ ++ arg |= vfsub_file_flags(file) & FASYNC; ++ err = setfl(/*unused fd*/-1, h_file, arg); ++ fput(h_file); /* instead of au_read_post() */ ++ ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* no one supports this operation, currently */ ++#if 0 /* reserved for future use */ ++static ssize_t aufs_sendpage(struct file *file, struct page *page, int offset, ++ size_t len, loff_t *pos, int more) ++{ ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++const struct file_operations aufs_file_fop = { ++ .owner = THIS_MODULE, ++ ++ .llseek = default_llseek, ++ ++ .read_iter = aufs_read_iter, ++ .write_iter = aufs_write_iter, ++ ++#ifdef CONFIG_AUFS_POLL ++ .poll = aufs_poll, ++#endif ++ .unlocked_ioctl = aufs_ioctl_nondir, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = aufs_compat_ioctl_nondir, ++#endif ++ .mmap = aufs_mmap, ++ .open = aufs_open_nondir, ++ .flush = aufs_flush_nondir, ++ .release = aufs_release_nondir, ++ .fsync = aufs_fsync_nondir, ++ .fasync = aufs_fasync, ++ /* .sendpage = aufs_sendpage, */ ++ .setfl = aufs_setfl, ++ .splice_write = aufs_splice_write, ++ .splice_read = aufs_splice_read, ++#if 0 /* reserved for future use */ ++ .aio_splice_write = aufs_aio_splice_write, ++ .aio_splice_read = aufs_aio_splice_read, ++#endif ++ .fallocate = aufs_fallocate, ++ .copy_file_range = aufs_copy_file_range ++}; +diff -Nurp linux-5.15.37/fs/aufs/fsctx.c linux-5.15.37-aufs/fs/aufs/fsctx.c +--- linux-5.15.37/fs/aufs/fsctx.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/fsctx.c 2022-04-08 20:22:30.613616524 +0300 +@@ -0,0 +1,1229 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2022 Junjiro R. Okajima ++ */ ++ ++/* ++ * fs context, aka new mount api ++ */ ++ ++#include ++#include "aufs.h" ++ ++struct au_fsctx_opts { ++ aufs_bindex_t bindex; ++ unsigned char skipped; ++ struct au_opt *opt, *opt_tail; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ struct au_opts opts; ++}; ++ ++/* stop extra interpretation of errno in mount(8), and strange error messages */ ++static int cvt_err(int err) ++{ ++ AuTraceErr(err); ++ ++ switch (err) { ++ case -ENOENT: ++ case -ENOTDIR: ++ case -EEXIST: ++ case -EIO: ++ err = -EINVAL; ++ } ++ return err; ++} ++ ++static int au_fsctx_reconfigure(struct fs_context *fc) ++{ ++ int err, do_dx; ++ unsigned int mntflags; ++ struct dentry *root; ++ struct super_block *sb; ++ struct inode *inode; ++ struct au_fsctx_opts *a = fc->fs_private; ++ ++ AuDbg("fc %p\n", fc); ++ ++ root = fc->root; ++ sb = root->d_sb; ++ err = si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (!err) { ++ di_write_lock_child(root); ++ err = au_opts_verify(sb, fc->sb_flags, /*pending*/0); ++ aufs_write_unlock(root); ++ } ++ ++ inode = d_inode(root); ++ inode_lock(inode); ++ err = si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out; ++ di_write_lock_child(root); ++ ++ /* au_opts_remount() may return an error */ ++ err = au_opts_remount(sb, &a->opts); ++ ++ if (au_ftest_opts(a->opts.flags, REFRESH)) ++ au_remount_refresh(sb, au_ftest_opts(a->opts.flags, ++ REFRESH_IDOP)); ++ ++ if (au_ftest_opts(a->opts.flags, REFRESH_DYAOP)) { ++ mntflags = au_mntflags(sb); ++ do_dx = !!au_opt_test(mntflags, DIO); ++ au_dy_arefresh(do_dx); ++ } ++ ++ au_fhsm_wrote_all(sb, /*force*/1); /* ?? */ ++ aufs_write_unlock(root); ++ ++out: ++ inode_unlock(inode); ++ err = cvt_err(err); ++ AuTraceErr(err); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_fsctx_fill_super(struct super_block *sb, struct fs_context *fc) ++{ ++ int err; ++ struct au_fsctx_opts *a = fc->fs_private; ++ struct au_sbinfo *sbinfo = a->sbinfo; ++ struct dentry *root; ++ struct inode *inode; ++ ++ sbinfo->si_sb = sb; ++ sb->s_fs_info = sbinfo; ++ kobject_get(&sbinfo->si_kobj); ++ ++ __si_write_lock(sb); ++ si_pid_set(sb); ++ au_sbilist_add(sb); ++ ++ /* all timestamps always follow the ones on the branch */ ++ sb->s_flags |= SB_NOATIME | SB_NODIRATIME; ++ sb->s_flags |= SB_I_VERSION; /* do we really need this? */ ++ sb->s_op = &aufs_sop; ++ sb->s_d_op = &aufs_dop; ++ sb->s_magic = AUFS_SUPER_MAGIC; ++ sb->s_maxbytes = 0; ++ sb->s_stack_depth = 1; ++ au_export_init(sb); ++ au_xattr_init(sb); ++ ++ err = au_alloc_root(sb); ++ if (unlikely(err)) { ++ si_write_unlock(sb); ++ goto out; ++ } ++ root = sb->s_root; ++ inode = d_inode(root); ++ ii_write_lock_parent(inode); ++ aufs_write_unlock(root); ++ ++ /* lock vfs_inode first, then aufs. */ ++ inode_lock(inode); ++ aufs_write_lock(root); ++ err = au_opts_mount(sb, &a->opts); ++ AuTraceErr(err); ++ if (!err && au_ftest_si(sbinfo, NO_DREVAL)) { ++ sb->s_d_op = &aufs_dop_noreval; ++ /* infofc(fc, "%ps", sb->s_d_op); */ ++ pr_info("%ps\n", sb->s_d_op); ++ au_refresh_dop(root, /*force_reval*/0); ++ sbinfo->si_iop_array = aufs_iop_nogetattr; ++ au_refresh_iop(inode, /*force_getattr*/0); ++ } ++ aufs_write_unlock(root); ++ inode_unlock(inode); ++ if (!err) ++ goto out; /* success */ ++ ++ dput(root); ++ sb->s_root = NULL; ++ ++out: ++ if (unlikely(err)) ++ kobject_put(&sbinfo->si_kobj); ++ AuTraceErr(err); ++ err = cvt_err(err); ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_fsctx_get_tree(struct fs_context *fc) ++{ ++ int err; ++ ++ AuDbg("fc %p\n", fc); ++ err = get_tree_nodev(fc, au_fsctx_fill_super); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_fsctx_dump(struct au_opts *opts) ++{ ++#ifdef CONFIG_AUFS_DEBUG ++ /* reduce stack space */ ++ union { ++ struct au_opt_add *add; ++ struct au_opt_del *del; ++ struct au_opt_mod *mod; ++ struct au_opt_xino *xino; ++ struct au_opt_xino_itrunc *xino_itrunc; ++ struct au_opt_wbr_create *create; ++ } u; ++ struct au_opt *opt; ++ ++ opt = opts->opt; ++ while (opt->type != Opt_tail) { ++ switch (opt->type) { ++ case Opt_add: ++ u.add = &opt->add; ++ AuDbg("add {b%d, %s, 0x%x, %p}\n", ++ u.add->bindex, u.add->pathname, u.add->perm, ++ u.add->path.dentry); ++ break; ++ case Opt_del: ++ fallthrough; ++ case Opt_idel: ++ u.del = &opt->del; ++ AuDbg("del {%s, %p}\n", ++ u.del->pathname, u.del->h_path.dentry); ++ break; ++ case Opt_mod: ++ fallthrough; ++ case Opt_imod: ++ u.mod = &opt->mod; ++ AuDbg("mod {%s, 0x%x, %p}\n", ++ u.mod->path, u.mod->perm, u.mod->h_root); ++ break; ++ case Opt_append: ++ u.add = &opt->add; ++ AuDbg("append {b%d, %s, 0x%x, %p}\n", ++ u.add->bindex, u.add->pathname, u.add->perm, ++ u.add->path.dentry); ++ break; ++ case Opt_prepend: ++ u.add = &opt->add; ++ AuDbg("prepend {b%d, %s, 0x%x, %p}\n", ++ u.add->bindex, u.add->pathname, u.add->perm, ++ u.add->path.dentry); ++ break; ++ ++ case Opt_dirwh: ++ AuDbg("dirwh %d\n", opt->dirwh); ++ break; ++ case Opt_rdcache: ++ AuDbg("rdcache %d\n", opt->rdcache); ++ break; ++ case Opt_rdblk: ++ AuDbg("rdblk %d\n", opt->rdblk); ++ break; ++ case Opt_rdhash: ++ AuDbg("rdhash %u\n", opt->rdhash); ++ break; ++ ++ case Opt_xino: ++ u.xino = &opt->xino; ++ AuDbg("xino {%s %pD}\n", u.xino->path, u.xino->file); ++ break; ++ ++#define au_fsctx_TF(name) \ ++ case Opt_##name: \ ++ if (opt->tf) \ ++ AuLabel(name); \ ++ else \ ++ AuLabel(no##name); \ ++ break; ++ ++ /* simple true/false flag */ ++ au_fsctx_TF(trunc_xino); ++ au_fsctx_TF(trunc_xib); ++ au_fsctx_TF(dirperm1); ++ au_fsctx_TF(plink); ++ au_fsctx_TF(shwh); ++ au_fsctx_TF(dio); ++ au_fsctx_TF(warn_perm); ++ au_fsctx_TF(verbose); ++ au_fsctx_TF(sum); ++ au_fsctx_TF(dirren); ++ au_fsctx_TF(acl); ++#undef au_fsctx_TF ++ ++ case Opt_trunc_xino_path: ++ fallthrough; ++ case Opt_itrunc_xino: ++ u.xino_itrunc = &opt->xino_itrunc; ++ AuDbg("trunc_xino %d\n", u.xino_itrunc->bindex); ++ break; ++ case Opt_noxino: ++ AuLabel(noxino); ++ break; ++ ++ case Opt_list_plink: ++ AuLabel(list_plink); ++ break; ++ case Opt_udba: ++ AuDbg("udba %d, %s\n", ++ opt->udba, au_optstr_udba(opt->udba)); ++ break; ++ case Opt_diropq_a: ++ AuLabel(diropq_a); ++ break; ++ case Opt_diropq_w: ++ AuLabel(diropq_w); ++ break; ++ case Opt_wsum: ++ AuLabel(wsum); ++ break; ++ case Opt_wbr_create: ++ u.create = &opt->wbr_create; ++ AuDbg("create %d, %s\n", u.create->wbr_create, ++ au_optstr_wbr_create(u.create->wbr_create)); ++ switch (u.create->wbr_create) { ++ case AuWbrCreate_MFSV: ++ fallthrough; ++ case AuWbrCreate_PMFSV: ++ AuDbg("%d sec\n", u.create->mfs_second); ++ break; ++ case AuWbrCreate_MFSRR: ++ fallthrough; ++ case AuWbrCreate_TDMFS: ++ AuDbg("%llu watermark\n", ++ u.create->mfsrr_watermark); ++ break; ++ case AuWbrCreate_MFSRRV: ++ fallthrough; ++ case AuWbrCreate_TDMFSV: ++ fallthrough; ++ case AuWbrCreate_PMFSRRV: ++ AuDbg("%llu watermark, %d sec\n", ++ u.create->mfsrr_watermark, ++ u.create->mfs_second); ++ break; ++ } ++ break; ++ case Opt_wbr_copyup: ++ AuDbg("copyup %d, %s\n", opt->wbr_copyup, ++ au_optstr_wbr_copyup(opt->wbr_copyup)); ++ break; ++ case Opt_fhsm_sec: ++ AuDbg("fhsm_sec %u\n", opt->fhsm_second); ++ break; ++ ++ default: ++ AuDbg("type %d\n", opt->type); ++ BUG(); ++ } ++ opt++; ++ } ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * For conditionally compiled mount options. ++ * Instead of fsparam_flag_no(), use this macro to distinguish ignore_silent. ++ */ ++#define au_ignore_flag(name, action) \ ++ fsparam_flag(name, action), \ ++ fsparam_flag("no" name, Opt_ignore_silent) ++ ++const struct fs_parameter_spec aufs_fsctx_paramspec[] = { ++ fsparam_string("br", Opt_br), ++ ++ /* "add=%d:%s" or "ins=%d:%s" */ ++ fsparam_string("add", Opt_add), ++ fsparam_string("ins", Opt_add), ++ fsparam_path("append", Opt_append), ++ fsparam_path("prepend", Opt_prepend), ++ ++ fsparam_path("del", Opt_del), ++ /* fsparam_s32("idel", Opt_idel), */ ++ fsparam_path("mod", Opt_mod), ++ /* fsparam_string("imod", Opt_imod), */ ++ ++ fsparam_s32("dirwh", Opt_dirwh), ++ ++ fsparam_path("xino", Opt_xino), ++ fsparam_flag("noxino", Opt_noxino), ++ fsparam_flag_no("trunc_xino", Opt_trunc_xino), ++ /* "trunc_xino_v=%d:%d" */ ++ /* fsparam_string("trunc_xino_v", Opt_trunc_xino_v), */ ++ fsparam_path("trunc_xino", Opt_trunc_xino_path), ++ fsparam_s32("itrunc_xino", Opt_itrunc_xino), ++ /* fsparam_path("zxino", Opt_zxino), */ ++ fsparam_flag_no("trunc_xib", Opt_trunc_xib), ++ ++#ifdef CONFIG_PROC_FS ++ fsparam_flag_no("plink", Opt_plink), ++#else ++ au_ignore_flag("plink", Opt_ignore), ++#endif ++ ++#ifdef CONFIG_AUFS_DEBUG ++ fsparam_flag("list_plink", Opt_list_plink), ++#endif ++ ++ fsparam_string("udba", Opt_udba), ++ ++ fsparam_flag_no("dio", Opt_dio), ++ ++#ifdef CONFIG_AUFS_DIRREN ++ fsparam_flag_no("dirren", Opt_dirren), ++#else ++ au_ignore_flag("dirren", Opt_ignore), ++#endif ++ ++#ifdef CONFIG_AUFS_FHSM ++ fsparam_s32("fhsm_sec", Opt_fhsm_sec), ++#else ++ fsparam_s32("fhsm_sec", Opt_ignore), ++#endif ++ ++ /* always | a | whiteouted | w */ ++ fsparam_string("diropq", Opt_diropq), ++ ++ fsparam_flag_no("warn_perm", Opt_warn_perm), ++ ++#ifdef CONFIG_AUFS_SHWH ++ fsparam_flag_no("shwh", Opt_shwh), ++#else ++ au_ignore_flag("shwh", Opt_err), ++#endif ++ ++ fsparam_flag_no("dirperm1", Opt_dirperm1), ++ ++ fsparam_flag_no("verbose", Opt_verbose), ++ fsparam_flag("v", Opt_verbose), ++ fsparam_flag("quiet", Opt_noverbose), ++ fsparam_flag("q", Opt_noverbose), ++ /* user-space may handle this */ ++ fsparam_flag("silent", Opt_noverbose), ++ ++ fsparam_flag_no("sum", Opt_sum), ++ fsparam_flag("wsum", Opt_wsum), ++ ++ fsparam_s32("rdcache", Opt_rdcache), ++ /* "def" or s32 */ ++ fsparam_string("rdblk", Opt_rdblk), ++ /* "def" or s32 */ ++ fsparam_string("rdhash", Opt_rdhash), ++ ++ fsparam_string("create", Opt_wbr_create), ++ fsparam_string("create_policy", Opt_wbr_create), ++ fsparam_string("cpup", Opt_wbr_copyup), ++ fsparam_string("copyup", Opt_wbr_copyup), ++ fsparam_string("copyup_policy", Opt_wbr_copyup), ++ ++ /* generic VFS flag */ ++#ifdef CONFIG_FS_POSIX_ACL ++ fsparam_flag_no("acl", Opt_acl), ++#else ++ au_ignore_flag("acl"), ++#endif ++ ++ /* internal use for the scripts */ ++ fsparam_string("si", Opt_ignore_silent), ++ ++ /* obsoleted, keep them temporary */ ++ fsparam_flag("nodlgt", Opt_ignore_silent), ++ fsparam_flag("clean_plink", Opt_ignore), ++ fsparam_string("dirs", Opt_br), ++ fsparam_u32("debug", Opt_ignore), ++ /* "whiteout" or "all" */ ++ fsparam_string("delete", Opt_ignore), ++ fsparam_string("imap", Opt_ignore), ++ ++ /* temporary workaround, due to old mount(8)? */ ++ fsparam_flag("relatime", Opt_ignore_silent), ++ ++ {} ++}; ++ ++static int au_fsctx_parse_do_add(struct fs_context *fc, struct au_opt *opt, ++ char *brspec, size_t speclen, ++ aufs_bindex_t bindex) ++{ ++ int err; ++ char *p; ++ ++ AuDbg("brspec %s\n", brspec); ++ ++ err = -ENOMEM; ++ if (!speclen) ++ speclen = strlen(brspec); ++ /* will be freed by au_fsctx_free() */ ++ p = kmemdup_nul(brspec, speclen, GFP_NOFS); ++ if (unlikely(!p)) { ++ errorfc(fc, "failed in %s", brspec); ++ goto out; ++ } ++ err = au_opt_add(opt, p, fc->sb_flags, bindex); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_fsctx_parse_br(struct fs_context *fc, char *brspec) ++{ ++ int err; ++ char *p; ++ struct au_fsctx_opts *a = fc->fs_private; ++ struct au_opt *opt = a->opt; ++ aufs_bindex_t bindex = a->bindex; ++ ++ AuDbg("brspec %s\n", brspec); ++ ++ err = -EINVAL; ++ while ((p = strsep(&brspec, ":")) && *p) { ++ err = au_fsctx_parse_do_add(fc, opt, p, /*len*/0, bindex); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ break; ++ bindex++; ++ opt++; ++ if (unlikely(opt > a->opt_tail)) { ++ err = -E2BIG; ++ bindex--; ++ opt--; ++ break; ++ } ++ opt->type = Opt_tail; ++ a->skipped = 1; ++ } ++ a->bindex = bindex; ++ a->opt = opt; ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_fsctx_parse_add(struct fs_context *fc, char *addspec) ++{ ++ int err, n; ++ char *p; ++ struct au_fsctx_opts *a = fc->fs_private; ++ struct au_opt *opt = a->opt; ++ ++ err = -EINVAL; ++ p = strchr(addspec, ':'); ++ if (unlikely(!p)) { ++ errorfc(fc, "bad arg in %s", addspec); ++ goto out; ++ } ++ *p++ = '\0'; ++ err = kstrtoint(addspec, 0, &n); ++ if (unlikely(err)) { ++ errorfc(fc, "bad integer in %s", addspec); ++ goto out; ++ } ++ AuDbg("n %d\n", n); ++ err = au_fsctx_parse_do_add(fc, opt, p, /*len*/0, n); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_fsctx_parse_del(struct fs_context *fc, struct au_opt_del *del, ++ struct fs_parameter *param) ++{ ++ int err; ++ ++ err = -ENOMEM; ++ /* will be freed by au_fsctx_free() */ ++ del->pathname = kmemdup_nul(param->string, param->size, GFP_NOFS); ++ if (unlikely(!del->pathname)) ++ goto out; ++ AuDbg("del %s\n", del->pathname); ++ err = vfsub_kern_path(del->pathname, AuOpt_LkupDirFlags, &del->h_path); ++ if (unlikely(err)) ++ errorfc(fc, "lookup failed %s (%d)", del->pathname, err); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++#if 0 /* reserved for future use */ ++static int au_fsctx_parse_idel(struct fs_context *fc, struct au_opt_del *del, ++ aufs_bindex_t bindex) ++{ ++ int err; ++ struct super_block *sb; ++ struct dentry *root; ++ struct au_fsctx_opts *a = fc->fs_private; ++ ++ sb = a->sb; ++ AuDebugOn(!sb); ++ ++ err = -EINVAL; ++ root = sb->s_root; ++ aufs_read_lock(root, AuLock_FLUSH); ++ if (bindex < 0 || au_sbbot(sb) < bindex) { ++ errorfc(fc, "out of bounds, %d", bindex); ++ goto out; ++ } ++ ++ err = 0; ++ del->h_path.dentry = dget(au_h_dptr(root, bindex)); ++ del->h_path.mnt = mntget(au_sbr_mnt(sb, bindex)); ++ ++out: ++ aufs_read_unlock(root, !AuLock_IR); ++ AuTraceErr(err); ++ return err; ++} ++#endif ++ ++static int au_fsctx_parse_mod(struct fs_context *fc, struct au_opt_mod *mod, ++ struct fs_parameter *param) ++{ ++ int err; ++ struct path path; ++ char *p; ++ ++ err = -ENOMEM; ++ /* will be freed by au_fsctx_free() */ ++ mod->path = kmemdup_nul(param->string, param->size, GFP_NOFS); ++ if (unlikely(!mod->path)) ++ goto out; ++ ++ err = -EINVAL; ++ p = strchr(mod->path, '='); ++ if (unlikely(!p)) { ++ errorfc(fc, "no permission %s", mod->path); ++ goto out; ++ } ++ ++ *p++ = 0; ++ err = vfsub_kern_path(mod->path, AuOpt_LkupDirFlags, &path); ++ if (unlikely(err)) { ++ errorfc(fc, "lookup failed %s (%d)", mod->path, err); ++ goto out; ++ } ++ ++ mod->perm = au_br_perm_val(p); ++ AuDbg("mod path %s, perm 0x%x, %s", mod->path, mod->perm, p); ++ mod->h_root = dget(path.dentry); ++ path_put(&path); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++#if 0 /* reserved for future use */ ++static int au_fsctx_parse_imod(struct fs_context *fc, struct au_opt_mod *mod, ++ char *ibrspec) ++{ ++ int err, n; ++ char *p; ++ struct super_block *sb; ++ struct dentry *root; ++ struct au_fsctx_opts *a = fc->fs_private; ++ ++ sb = a->sb; ++ AuDebugOn(!sb); ++ ++ err = -EINVAL; ++ p = strchr(ibrspec, ':'); ++ if (unlikely(!p)) { ++ errorfc(fc, "no index, %s", ibrspec); ++ goto out; ++ } ++ *p++ = '\0'; ++ err = kstrtoint(ibrspec, 0, &n); ++ if (unlikely(err)) { ++ errorfc(fc, "bad integer in %s", ibrspec); ++ goto out; ++ } ++ AuDbg("n %d\n", n); ++ ++ root = sb->s_root; ++ aufs_read_lock(root, AuLock_FLUSH); ++ if (n < 0 || au_sbbot(sb) < n) { ++ errorfc(fc, "out of bounds, %d", bindex); ++ goto out_root; ++ } ++ ++ err = 0; ++ mod->perm = au_br_perm_val(p); ++ AuDbg("mod path %s, perm 0x%x, %s\n", ++ mod->path, mod->perm, p); ++ mod->h_root = dget(au_h_dptr(root, bindex)); ++ ++out_root: ++ aufs_read_unlock(root, !AuLock_IR); ++out: ++ AuTraceErr(err); ++ return err; ++} ++#endif ++ ++static int au_fsctx_parse_xino(struct fs_context *fc, ++ struct au_opt_xino *xino, ++ struct fs_parameter *param) ++{ ++ int err; ++ struct au_fsctx_opts *a = fc->fs_private; ++ ++ err = -ENOMEM; ++ /* will be freed by au_opts_free() */ ++ xino->path = kmemdup_nul(param->string, param->size, GFP_NOFS); ++ if (unlikely(!xino->path)) ++ goto out; ++ AuDbg("path %s\n", xino->path); ++ ++ xino->file = au_xino_create(a->sb, xino->path, /*silent*/0, ++ /*wbrtop*/0); ++ err = PTR_ERR(xino->file); ++ if (IS_ERR(xino->file)) { ++ xino->file = NULL; ++ goto out; ++ } ++ ++ err = 0; ++ if (unlikely(a->sb && xino->file->f_path.dentry->d_sb == a->sb)) { ++ err = -EINVAL; ++ errorfc(fc, "%s must be outside", xino->path); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static ++int au_fsctx_parse_xino_itrunc_path(struct fs_context *fc, ++ struct au_opt_xino_itrunc *xino_itrunc, ++ char *pathname) ++{ ++ int err; ++ aufs_bindex_t bbot, bindex; ++ struct path path; ++ struct dentry *root; ++ struct au_fsctx_opts *a = fc->fs_private; ++ ++ AuDebugOn(!a->sb); ++ ++ err = vfsub_kern_path(pathname, AuOpt_LkupDirFlags, &path); ++ if (unlikely(err)) { ++ errorfc(fc, "lookup failed %s (%d)", pathname, err); ++ goto out; ++ } ++ ++ xino_itrunc->bindex = -1; ++ root = a->sb->s_root; ++ aufs_read_lock(root, AuLock_FLUSH); ++ bbot = au_sbbot(a->sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ if (au_h_dptr(root, bindex) == path.dentry) { ++ xino_itrunc->bindex = bindex; ++ break; ++ } ++ } ++ aufs_read_unlock(root, !AuLock_IR); ++ path_put(&path); ++ ++ if (unlikely(xino_itrunc->bindex < 0)) { ++ err = -EINVAL; ++ errorfc(fc, "no such branch %s", pathname); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_fsctx_parse_xino_itrunc(struct fs_context *fc, ++ struct au_opt_xino_itrunc *xino_itrunc, ++ unsigned int bindex) ++{ ++ int err; ++ aufs_bindex_t bbot; ++ struct super_block *sb; ++ struct au_fsctx_opts *a = fc->fs_private; ++ ++ sb = a->sb; ++ AuDebugOn(!sb); ++ ++ err = 0; ++ si_noflush_read_lock(sb); ++ bbot = au_sbbot(sb); ++ si_read_unlock(sb); ++ if (bindex <= bbot) ++ xino_itrunc->bindex = bindex; ++ else { ++ err = -EINVAL; ++ errorfc(fc, "out of bounds, %u", bindex); ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_fsctx_parse_param(struct fs_context *fc, struct fs_parameter *param) ++{ ++ int err, token; ++ struct fs_parse_result result; ++ struct au_fsctx_opts *a = fc->fs_private; ++ struct au_opt *opt = a->opt; ++ ++ AuDbg("fc %p, param {key %s, string %s}\n", ++ fc, param->key, param->string); ++ err = fs_parse(fc, aufs_fsctx_paramspec, param, &result); ++ if (unlikely(err < 0)) ++ goto out; ++ token = err; ++ AuDbg("token %d, res{negated %d, uint64 %llu}\n", ++ token, result.negated, result.uint_64); ++ ++ err = -EINVAL; ++ a->skipped = 0; ++ switch (token) { ++ case Opt_br: ++ err = au_fsctx_parse_br(fc, param->string); ++ break; ++ case Opt_add: ++ err = au_fsctx_parse_add(fc, param->string); ++ break; ++ case Opt_append: ++ err = au_fsctx_parse_do_add(fc, opt, param->string, param->size, ++ /*dummy bindex*/1); ++ break; ++ case Opt_prepend: ++ err = au_fsctx_parse_do_add(fc, opt, param->string, param->size, ++ /*bindex*/0); ++ break; ++ ++ case Opt_del: ++ err = au_fsctx_parse_del(fc, &opt->del, param); ++ break; ++#if 0 /* reserved for future use */ ++ case Opt_idel: ++ if (!a->sb) { ++ err = 0; ++ a->skipped = 1; ++ break; ++ } ++ del->pathname = "(indexed)"; ++ err = au_opts_parse_idel(fc, &opt->del, result.uint_32); ++ break; ++#endif ++ ++ case Opt_mod: ++ err = au_fsctx_parse_mod(fc, &opt->mod, param); ++ break; ++#ifdef IMOD /* reserved for future use */ ++ case Opt_imod: ++ if (!a->sb) { ++ err = 0; ++ a->skipped = 1; ++ break; ++ } ++ u.mod->path = "(indexed)"; ++ err = au_opts_parse_imod(fc, &opt->mod, param->string); ++ break; ++#endif ++ ++ case Opt_xino: ++ err = au_fsctx_parse_xino(fc, &opt->xino, param); ++ break; ++ case Opt_trunc_xino_path: ++ if (!a->sb) { ++ errorfc(fc, "no such branch %s", param->string); ++ break; ++ } ++ err = au_fsctx_parse_xino_itrunc_path(fc, &opt->xino_itrunc, ++ param->string); ++ break; ++#if 0 ++ case Opt_trunc_xino_v: ++ if (!a->sb) { ++ err = 0; ++ a->skipped = 1; ++ break; ++ } ++ err = au_fsctx_parse_xino_itrunc_path(fc, &opt->xino_itrunc, ++ param->string); ++ break; ++#endif ++ case Opt_itrunc_xino: ++ if (!a->sb) { ++ errorfc(fc, "out of bounds %s", param->string); ++ break; ++ } ++ err = au_fsctx_parse_xino_itrunc(fc, &opt->xino_itrunc, ++ result.int_32); ++ break; ++ ++ case Opt_dirwh: ++ err = 0; ++ opt->dirwh = result.int_32; ++ break; ++ ++ case Opt_rdcache: ++ if (unlikely(result.int_32 > AUFS_RDCACHE_MAX)) { ++ errorfc(fc, "rdcache must be smaller than %d", ++ AUFS_RDCACHE_MAX); ++ break; ++ } ++ err = 0; ++ opt->rdcache = result.int_32; ++ break; ++ ++ case Opt_rdblk: ++ err = 0; ++ opt->rdblk = AUFS_RDBLK_DEF; ++ if (!strcmp(param->string, "def")) ++ break; ++ ++ err = kstrtoint(param->string, 0, &result.int_32); ++ if (unlikely(err)) { ++ errorfc(fc, "bad value in %s", param->key); ++ break; ++ } ++ err = -EINVAL; ++ if (unlikely(result.int_32 < 0 ++ || result.int_32 > KMALLOC_MAX_SIZE)) { ++ errorfc(fc, "bad value in %s", param->key); ++ break; ++ } ++ if (unlikely(result.int_32 && result.int_32 < NAME_MAX)) { ++ errorfc(fc, "rdblk must be larger than %d", NAME_MAX); ++ break; ++ } ++ err = 0; ++ opt->rdblk = result.int_32; ++ break; ++ ++ case Opt_rdhash: ++ err = 0; ++ opt->rdhash = AUFS_RDHASH_DEF; ++ if (!strcmp(param->string, "def")) ++ break; ++ ++ err = kstrtoint(param->string, 0, &result.int_32); ++ if (unlikely(err)) { ++ errorfc(fc, "bad value in %s", param->key); ++ break; ++ } ++ /* how about zero? */ ++ if (result.int_32 < 0 ++ || result.int_32 * sizeof(struct hlist_head) ++ > KMALLOC_MAX_SIZE) { ++ err = -EINVAL; ++ errorfc(fc, "bad integer in %s", param->key); ++ break; ++ } ++ opt->rdhash = result.int_32; ++ break; ++ ++ case Opt_diropq: ++ /* ++ * As other options, fs/aufs/opts.c can handle these strings by ++ * match_token(). But "diropq=" is deprecated now and will ++ * never have other value. So simple strcmp() is enough here. ++ */ ++ if (!strcmp(param->string, "a") || ++ !strcmp(param->string, "always")) { ++ err = 0; ++ opt->type = Opt_diropq_a; ++ } else if (!strcmp(param->string, "w") || ++ !strcmp(param->string, "whiteouted")) { ++ err = 0; ++ opt->type = Opt_diropq_w; ++ } else ++ errorfc(fc, "unknown value %s", param->string); ++ break; ++ ++ case Opt_udba: ++ opt->udba = au_udba_val(param->string); ++ if (opt->udba >= 0) ++ err = 0; ++ else ++ errorf(fc, "wrong value, %s", param->string); ++ break; ++ ++ case Opt_wbr_create: ++ opt->wbr_create.wbr_create ++ = au_wbr_create_val(param->string, &opt->wbr_create); ++ if (opt->wbr_create.wbr_create >= 0) ++ err = 0; ++ else ++ errorf(fc, "wrong value, %s", param->key); ++ break; ++ ++ case Opt_wbr_copyup: ++ opt->wbr_copyup = au_wbr_copyup_val(param->string); ++ if (opt->wbr_copyup >= 0) ++ err = 0; ++ else ++ errorfc(fc, "wrong value, %s", param->key); ++ break; ++ ++ case Opt_fhsm_sec: ++ if (unlikely(result.int_32 < 0)) { ++ errorfc(fc, "bad integer in %s\n", param->key); ++ break; ++ } ++ err = 0; ++ if (sysaufs_brs) ++ opt->fhsm_second = result.int_32; ++ else ++ warnfc(fc, "ignored %s %s", param->key, param->string); ++ break; ++ ++ /* simple true/false flag */ ++#define au_fsctx_TF(name) \ ++ case Opt_##name: \ ++ err = 0; \ ++ opt->tf = !result.negated; \ ++ break; ++ au_fsctx_TF(trunc_xino); ++ au_fsctx_TF(trunc_xib); ++ au_fsctx_TF(dirperm1); ++ au_fsctx_TF(plink); ++ au_fsctx_TF(shwh); ++ au_fsctx_TF(dio); ++ au_fsctx_TF(warn_perm); ++ au_fsctx_TF(verbose); ++ au_fsctx_TF(sum); ++ au_fsctx_TF(dirren); ++ au_fsctx_TF(acl); ++#undef au_fsctx_TF ++ ++ case Opt_noverbose: ++ err = 0; ++ opt->type = Opt_verbose; ++ opt->tf = false; ++ break; ++ ++ case Opt_noxino: ++ fallthrough; ++ case Opt_list_plink: ++ fallthrough; ++ case Opt_wsum: ++ err = 0; ++ break; ++ ++ case Opt_ignore: ++ warnfc(fc, "ignored %s", param->key); ++ fallthrough; ++ case Opt_ignore_silent: ++ a->skipped = 1; ++ err = 0; ++ break; ++ default: ++ a->skipped = 1; ++ err = -ENOPARAM; ++ break; ++ } ++ if (unlikely(err)) ++ goto out; ++ if (a->skipped) ++ goto out; ++ ++ switch (token) { ++ case Opt_br: ++ fallthrough; ++ case Opt_noverbose: ++ fallthrough; ++ case Opt_diropq: ++ break; ++ default: ++ opt->type = token; ++ break; ++ } ++ opt++; ++ if (unlikely(opt > a->opt_tail)) { ++ err = -E2BIG; ++ opt--; ++ } ++ opt->type = Opt_tail; ++ a->opt = opt; ++ ++out: ++ return err; ++} ++ ++/* ++ * these options accept both 'name=val' and 'name:val' form. ++ * some accept optional '=' in its value. ++ * eg. br:/br1=rw:/br2=ro and br=/br1=rw:/br2=ro ++ */ ++static inline unsigned int is_colonopt(char *str) ++{ ++#define do_test(name) \ ++ if (!strncmp(str, name ":", sizeof(name))) \ ++ return sizeof(name) - 1; ++ do_test("br"); ++ do_test("add"); ++ do_test("ins"); ++ do_test("append"); ++ do_test("prepend"); ++ do_test("del"); ++ /* do_test("idel"); */ ++ do_test("mod"); ++ /* do_test("imod"); */ ++#undef do_test ++ ++ return 0; ++} ++ ++static int au_fsctx_parse_monolithic(struct fs_context *fc, void *data) ++{ ++ int err; ++ unsigned int u; ++ char *str; ++ struct au_fsctx_opts *a = fc->fs_private; ++ ++ str = data; ++ AuDbg("str %s\n", str); ++ while (str) { ++ u = is_colonopt(str); ++ if (u) ++ str[u] = '='; ++ str = strchr(str, ','); ++ if (!str) ++ break; ++ str++; ++ } ++ str = data; ++ AuDbg("str %s\n", str); ++ ++ err = generic_parse_monolithic(fc, str); ++ AuTraceErr(err); ++ au_fsctx_dump(&a->opts); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_fsctx_opts_free(struct au_opts *opts) ++{ ++ struct au_opt *opt; ++ ++ opt = opts->opt; ++ while (opt->type != Opt_tail) { ++ switch (opt->type) { ++ case Opt_add: ++ fallthrough; ++ case Opt_append: ++ fallthrough; ++ case Opt_prepend: ++ kfree(opt->add.pathname); ++ path_put(&opt->add.path); ++ break; ++ case Opt_del: ++ kfree(opt->del.pathname); ++ fallthrough; ++ case Opt_idel: ++ path_put(&opt->del.h_path); ++ break; ++ case Opt_mod: ++ kfree(opt->mod.path); ++ fallthrough; ++ case Opt_imod: ++ dput(opt->mod.h_root); ++ break; ++ case Opt_xino: ++ kfree(opt->xino.path); ++ fput(opt->xino.file); ++ break; ++ } ++ opt++; ++ } ++} ++ ++static void au_fsctx_free(struct fs_context *fc) ++{ ++ struct au_fsctx_opts *a = fc->fs_private; ++ ++ /* fs_type=%p, root=%pD */ ++ AuDbg("fc %p{sb_flags 0x%x, sb_flags_mask 0x%x, purpose %u\n", ++ fc, fc->sb_flags, fc->sb_flags_mask, fc->purpose); ++ ++ kobject_put(&a->sbinfo->si_kobj); ++ au_fsctx_opts_free(&a->opts); ++ free_page((unsigned long)a->opts.opt); ++ au_kfree_rcu(a); ++} ++ ++static const struct fs_context_operations au_fsctx_ops = { ++ .free = au_fsctx_free, ++ .parse_param = au_fsctx_parse_param, ++ .parse_monolithic = au_fsctx_parse_monolithic, ++ .get_tree = au_fsctx_get_tree, ++ .reconfigure = au_fsctx_reconfigure ++ /* ++ * nfs4 requires ->dup()? No. ++ * I don't know what is this ->dup() for. ++ */ ++}; ++ ++int aufs_fsctx_init(struct fs_context *fc) ++{ ++ int err; ++ struct au_fsctx_opts *a; ++ ++ /* fs_type=%p, root=%pD */ ++ AuDbg("fc %p{sb_flags 0x%x, sb_flags_mask 0x%x, purpose %u\n", ++ fc, fc->sb_flags, fc->sb_flags_mask, fc->purpose); ++ ++ /* they will be freed by au_fsctx_free() */ ++ err = -ENOMEM; ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ a->bindex = 0; ++ a->opts.opt = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!a->opts.opt)) ++ goto out_a; ++ a->opt = a->opts.opt; ++ a->opt->type = Opt_tail; ++ a->opts.max_opt = PAGE_SIZE / sizeof(*a->opts.opt); ++ a->opt_tail = a->opt + a->opts.max_opt - 1; ++ a->opts.sb_flags = fc->sb_flags; ++ ++ a->sb = NULL; ++ if (fc->root) { ++ AuDebugOn(fc->purpose != FS_CONTEXT_FOR_RECONFIGURE); ++ a->opts.flags = AuOpts_REMOUNT; ++ a->sb = fc->root->d_sb; ++ a->sbinfo = au_sbi(a->sb); ++ kobject_get(&a->sbinfo->si_kobj); ++ } else { ++ a->sbinfo = au_si_alloc(a->sb); ++ AuDebugOn(!a->sbinfo); ++ err = PTR_ERR(a->sbinfo); ++ if (IS_ERR(a->sbinfo)) ++ goto out_opt; ++ au_rw_write_unlock(&a->sbinfo->si_rwsem); ++ } ++ ++ err = 0; ++ fc->fs_private = a; ++ fc->ops = &au_fsctx_ops; ++ goto out; /* success */ ++ ++out_opt: ++ free_page((unsigned long)a->opts.opt); ++out_a: ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} +diff -Nurp linux-5.15.37/fs/aufs/fstype.h linux-5.15.37-aufs/fs/aufs/fstype.h +--- linux-5.15.37/fs/aufs/fstype.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/fstype.h 2022-04-08 20:22:30.613616524 +0300 +@@ -0,0 +1,388 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * judging filesystem type ++ */ ++ ++#ifndef __AUFS_FSTYPE_H__ ++#define __AUFS_FSTYPE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++ ++static inline int au_test_aufs(struct super_block *sb) ++{ ++ return sb->s_magic == AUFS_SUPER_MAGIC; ++} ++ ++static inline const char *au_sbtype(struct super_block *sb) ++{ ++ return sb->s_type->name; ++} ++ ++static inline int au_test_iso9660(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_ISO9660_FS) ++ return sb->s_magic == ISOFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_romfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_ROMFS_FS) ++ return sb->s_magic == ROMFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_cramfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_CRAMFS) ++ return sb->s_magic == CRAMFS_MAGIC; ++#endif ++ return 0; ++} ++ ++static inline int au_test_nfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_NFS_FS) ++ return sb->s_magic == NFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_fuse(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_FUSE_FS) ++ return sb->s_magic == FUSE_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_xfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_XFS_FS) ++ return sb->s_magic == XFS_SB_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_tmpfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_TMPFS ++ return sb->s_magic == TMPFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_ecryptfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_ECRYPT_FS) ++ return !strcmp(au_sbtype(sb), "ecryptfs"); ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_ramfs(struct super_block *sb) ++{ ++ return sb->s_magic == RAMFS_MAGIC; ++} ++ ++static inline int au_test_ubifs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_UBIFS_FS) ++ return sb->s_magic == UBIFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_procfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_PROC_FS ++ return sb->s_magic == PROC_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_sysfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_SYSFS ++ return sb->s_magic == SYSFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_configfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_CONFIGFS_FS) ++ return sb->s_magic == CONFIGFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_minix(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_MINIX_FS) ++ return sb->s_magic == MINIX3_SUPER_MAGIC ++ || sb->s_magic == MINIX2_SUPER_MAGIC ++ || sb->s_magic == MINIX2_SUPER_MAGIC2 ++ || sb->s_magic == MINIX_SUPER_MAGIC ++ || sb->s_magic == MINIX_SUPER_MAGIC2; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_fat(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_FAT_FS) ++ return sb->s_magic == MSDOS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_msdos(struct super_block *sb) ++{ ++ return au_test_fat(sb); ++} ++ ++static inline int au_test_vfat(struct super_block *sb) ++{ ++ return au_test_fat(sb); ++} ++ ++static inline int au_test_securityfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_SECURITYFS ++ return sb->s_magic == SECURITYFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_squashfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_SQUASHFS) ++ return sb->s_magic == SQUASHFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_btrfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_BTRFS_FS) ++ return sb->s_magic == BTRFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_xenfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_XENFS) ++ return sb->s_magic == XENFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_debugfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_DEBUG_FS ++ return sb->s_magic == DEBUGFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_nilfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_NILFS) ++ return sb->s_magic == NILFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_hfsplus(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_HFSPLUS_FS) ++ return sb->s_magic == HFSPLUS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * they can't be an aufs branch. ++ */ ++static inline int au_test_fs_unsuppoted(struct super_block *sb) ++{ ++ return ++#ifndef CONFIG_AUFS_BR_RAMFS ++ au_test_ramfs(sb) || ++#endif ++ au_test_procfs(sb) ++ || au_test_sysfs(sb) ++ || au_test_configfs(sb) ++ || au_test_debugfs(sb) ++ || au_test_securityfs(sb) ++ || au_test_xenfs(sb) ++ || au_test_ecryptfs(sb) ++ /* || !strcmp(au_sbtype(sb), "unionfs") */ ++ || au_test_aufs(sb); /* will be supported in next version */ ++} ++ ++static inline int au_test_fs_remote(struct super_block *sb) ++{ ++ return !au_test_tmpfs(sb) ++#ifdef CONFIG_AUFS_BR_RAMFS ++ && !au_test_ramfs(sb) ++#endif ++ && !(sb->s_type->fs_flags & FS_REQUIRES_DEV); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * Note: these functions (below) are created after reading ->getattr() in all ++ * filesystems under linux/fs. it means we have to do so in every update... ++ */ ++ ++/* ++ * some filesystems require getattr to refresh the inode attributes before ++ * referencing. ++ * in most cases, we can rely on the inode attribute in NFS (or every remote fs) ++ * and leave the work for d_revalidate() ++ */ ++static inline int au_test_fs_refresh_iattr(struct super_block *sb) ++{ ++ return au_test_nfs(sb) ++ || au_test_fuse(sb) ++ /* || au_test_btrfs(sb) */ /* untested */ ++ ; ++} ++ ++/* ++ * filesystems which don't maintain i_size or i_blocks. ++ */ ++static inline int au_test_fs_bad_iattr_size(struct super_block *sb) ++{ ++ return au_test_xfs(sb) ++ || au_test_btrfs(sb) ++ || au_test_ubifs(sb) ++ || au_test_hfsplus(sb) /* maintained, but incorrect */ ++ /* || au_test_minix(sb) */ /* untested */ ++ ; ++} ++ ++/* ++ * filesystems which don't store the correct value in some of their inode ++ * attributes. ++ */ ++static inline int au_test_fs_bad_iattr(struct super_block *sb) ++{ ++ return au_test_fs_bad_iattr_size(sb) ++ || au_test_fat(sb) ++ || au_test_msdos(sb) ++ || au_test_vfat(sb); ++} ++ ++/* they don't check i_nlink in link(2) */ ++static inline int au_test_fs_no_limit_nlink(struct super_block *sb) ++{ ++ return au_test_tmpfs(sb) ++#ifdef CONFIG_AUFS_BR_RAMFS ++ || au_test_ramfs(sb) ++#endif ++ || au_test_ubifs(sb) ++ || au_test_hfsplus(sb); ++} ++ ++/* ++ * filesystems which sets S_NOATIME and S_NOCMTIME. ++ */ ++static inline int au_test_fs_notime(struct super_block *sb) ++{ ++ return au_test_nfs(sb) ++ || au_test_fuse(sb) ++ || au_test_ubifs(sb) ++ ; ++} ++ ++/* temporary support for i#1 in cramfs */ ++static inline int au_test_fs_unique_ino(struct inode *inode) ++{ ++ if (au_test_cramfs(inode->i_sb)) ++ return inode->i_ino != 1; ++ return 1; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * the filesystem where the xino files placed must support i/o after unlink and ++ * maintain i_size and i_blocks. ++ */ ++static inline int au_test_fs_bad_xino(struct super_block *sb) ++{ ++ return au_test_fs_remote(sb) ++ || au_test_fs_bad_iattr_size(sb) ++ /* don't want unnecessary work for xino */ ++ || au_test_aufs(sb) ++ || au_test_ecryptfs(sb) ++ || au_test_nilfs(sb); ++} ++ ++static inline int au_test_fs_trunc_xino(struct super_block *sb) ++{ ++ return au_test_tmpfs(sb) ++ || au_test_ramfs(sb); ++} ++ ++/* ++ * test if the @sb is real-readonly. ++ */ ++static inline int au_test_fs_rr(struct super_block *sb) ++{ ++ return au_test_squashfs(sb) ++ || au_test_iso9660(sb) ++ || au_test_cramfs(sb) ++ || au_test_romfs(sb); ++} ++ ++/* ++ * test if the @inode is nfs with 'noacl' option ++ * NFS always sets SB_POSIXACL regardless its mount option 'noacl.' ++ */ ++static inline int au_test_nfs_noacl(struct inode *inode) ++{ ++ return au_test_nfs(inode->i_sb) ++ /* && IS_POSIXACL(inode) */ ++ && !nfs_server_capable(inode, NFS_CAP_ACLS); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_FSTYPE_H__ */ +diff -Nurp linux-5.15.37/fs/aufs/hbl.h linux-5.15.37-aufs/fs/aufs/hbl.h +--- linux-5.15.37/fs/aufs/hbl.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/hbl.h 2022-04-08 20:22:30.613616524 +0300 +@@ -0,0 +1,52 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2017-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * helpers for hlist_bl.h ++ */ ++ ++#ifndef __AUFS_HBL_H__ ++#define __AUFS_HBL_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++static inline void au_hbl_add(struct hlist_bl_node *node, ++ struct hlist_bl_head *hbl) ++{ ++ hlist_bl_lock(hbl); ++ hlist_bl_add_head(node, hbl); ++ hlist_bl_unlock(hbl); ++} ++ ++static inline void au_hbl_del(struct hlist_bl_node *node, ++ struct hlist_bl_head *hbl) ++{ ++ hlist_bl_lock(hbl); ++ hlist_bl_del(node); ++ hlist_bl_unlock(hbl); ++} ++ ++#define au_hbl_for_each(pos, head) \ ++ for (pos = hlist_bl_first(head); \ ++ pos; \ ++ pos = pos->next) ++ ++static inline unsigned long au_hbl_count(struct hlist_bl_head *hbl) ++{ ++ unsigned long cnt; ++ struct hlist_bl_node *pos; ++ ++ cnt = 0; ++ hlist_bl_lock(hbl); ++ au_hbl_for_each(pos, hbl) ++ cnt++; ++ hlist_bl_unlock(hbl); ++ return cnt; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_HBL_H__ */ +diff --git a/fs/aufs/hfsnotify.c b/fs/aufs/hfsnotify.c +new file mode 100644 +index 000000000000..c2c7766d6cf1 +--- /dev/null ++++ b/fs/aufs/hfsnotify.c +@@ -0,0 +1,275 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * fsnotify for the lower directories ++ */ ++ ++#include "aufs.h" ++ ++/* FS_IN_IGNORED is unnecessary */ ++static const __u32 AuHfsnMask = (FS_MOVED_TO | FS_MOVED_FROM | FS_DELETE ++ | FS_CREATE | FS_EVENT_ON_CHILD); ++static DECLARE_WAIT_QUEUE_HEAD(au_hfsn_wq); ++static __cacheline_aligned_in_smp atomic64_t au_hfsn_ifree = ATOMIC64_INIT(0); ++ ++static void au_hfsn_free_mark(struct fsnotify_mark *mark) ++{ ++ struct au_hnotify *hn = container_of(mark, struct au_hnotify, ++ hn_mark); ++ /* AuDbg("here\n"); */ ++ au_cache_free_hnotify(hn); ++ smp_mb__before_atomic(); /* for atomic64_dec */ ++ if (atomic64_dec_and_test(&au_hfsn_ifree)) ++ wake_up(&au_hfsn_wq); ++} ++ ++static int au_hfsn_alloc(struct au_hinode *hinode) ++{ ++ int err; ++ struct au_hnotify *hn; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct fsnotify_mark *mark; ++ aufs_bindex_t bindex; ++ ++ hn = hinode->hi_notify; ++ sb = hn->hn_aufs_inode->i_sb; ++ bindex = au_br_index(sb, hinode->hi_id); ++ br = au_sbr(sb, bindex); ++ AuDebugOn(!br->br_hfsn); ++ ++ mark = &hn->hn_mark; ++ fsnotify_init_mark(mark, br->br_hfsn->hfsn_group); ++ mark->mask = AuHfsnMask; ++ /* ++ * by udba rename or rmdir, aufs assign a new inode to the known ++ * h_inode, so specify 1 to allow dups. ++ */ ++ lockdep_off(); ++ err = fsnotify_add_inode_mark(mark, hinode->hi_inode, /*allow_dups*/1); ++ lockdep_on(); ++ ++ return err; ++} ++ ++static int au_hfsn_free(struct au_hinode *hinode, struct au_hnotify *hn) ++{ ++ struct fsnotify_mark *mark; ++ unsigned long long ull; ++ struct fsnotify_group *group; ++ ++ ull = atomic64_inc_return(&au_hfsn_ifree); ++ BUG_ON(!ull); ++ ++ mark = &hn->hn_mark; ++ spin_lock(&mark->lock); ++ group = mark->group; ++ fsnotify_get_group(group); ++ spin_unlock(&mark->lock); ++ lockdep_off(); ++ fsnotify_destroy_mark(mark, group); ++ fsnotify_put_mark(mark); ++ fsnotify_put_group(group); ++ lockdep_on(); ++ ++ /* free hn by myself */ ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_hfsn_ctl(struct au_hinode *hinode, int do_set) ++{ ++ struct fsnotify_mark *mark; ++ ++ mark = &hinode->hi_notify->hn_mark; ++ spin_lock(&mark->lock); ++ if (do_set) { ++ AuDebugOn(mark->mask & AuHfsnMask); ++ mark->mask |= AuHfsnMask; ++ } else { ++ AuDebugOn(!(mark->mask & AuHfsnMask)); ++ mark->mask &= ~AuHfsnMask; ++ } ++ spin_unlock(&mark->lock); ++ /* fsnotify_recalc_inode_mask(hinode->hi_inode); */ ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* #define AuDbgHnotify */ ++#ifdef AuDbgHnotify ++static char *au_hfsn_name(u32 mask) ++{ ++#ifdef CONFIG_AUFS_DEBUG ++#define test_ret(flag) \ ++ do { \ ++ if (mask & flag) \ ++ return #flag; \ ++ } while (0) ++ test_ret(FS_ACCESS); ++ test_ret(FS_MODIFY); ++ test_ret(FS_ATTRIB); ++ test_ret(FS_CLOSE_WRITE); ++ test_ret(FS_CLOSE_NOWRITE); ++ test_ret(FS_OPEN); ++ test_ret(FS_MOVED_FROM); ++ test_ret(FS_MOVED_TO); ++ test_ret(FS_CREATE); ++ test_ret(FS_DELETE); ++ test_ret(FS_DELETE_SELF); ++ test_ret(FS_MOVE_SELF); ++ test_ret(FS_UNMOUNT); ++ test_ret(FS_Q_OVERFLOW); ++ test_ret(FS_IN_IGNORED); ++ test_ret(FS_ISDIR); ++ test_ret(FS_IN_ONESHOT); ++ test_ret(FS_EVENT_ON_CHILD); ++ return ""; ++#undef test_ret ++#else ++ return "??"; ++#endif ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_hfsn_free_group(struct fsnotify_group *group) ++{ ++ struct au_br_hfsnotify *hfsn = group->private; ++ ++ /* AuDbg("here\n"); */ ++ au_kfree_try_rcu(hfsn); ++} ++ ++static int au_hfsn_handle_event(struct fsnotify_group *group, ++ u32 mask, const void *data, int data_type, ++ struct inode *dir, ++ const struct qstr *file_name, u32 cookie, ++ struct fsnotify_iter_info *iter_info) ++{ ++ int err; ++ struct au_hnotify *hnotify; ++ struct inode *h_dir, *h_inode; ++ struct fsnotify_mark *inode_mark; ++ ++ AuDebugOn(data_type != FSNOTIFY_EVENT_INODE); ++ ++ err = 0; ++ /* if FS_UNMOUNT happens, there must be another bug */ ++ AuDebugOn(mask & FS_UNMOUNT); ++ if (mask & (FS_IN_IGNORED | FS_UNMOUNT)) ++ goto out; ++ ++ h_dir = dir; ++ h_inode = NULL; ++#ifdef AuDbgHnotify ++ au_debug_on(); ++ if (1 || h_child_qstr.len != sizeof(AUFS_XINO_FNAME) - 1 ++ || strncmp(h_child_qstr.name, AUFS_XINO_FNAME, h_child_qstr.len)) { ++ AuDbg("i%lu, mask 0x%x %s, hcname %.*s, hi%lu\n", ++ h_dir->i_ino, mask, au_hfsn_name(mask), ++ AuLNPair(&h_child_qstr), h_inode ? h_inode->i_ino : 0); ++ /* WARN_ON(1); */ ++ } ++ au_debug_off(); ++#endif ++ ++ inode_mark = fsnotify_iter_inode_mark(iter_info); ++ AuDebugOn(!inode_mark); ++ hnotify = container_of(inode_mark, struct au_hnotify, hn_mark); ++ err = au_hnotify(h_dir, hnotify, mask, file_name, h_inode); ++ ++out: ++ return err; ++} ++ ++static struct fsnotify_ops au_hfsn_ops = { ++ .handle_event = au_hfsn_handle_event, ++ .free_group_priv = au_hfsn_free_group, ++ .free_mark = au_hfsn_free_mark ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_hfsn_fin_br(struct au_branch *br) ++{ ++ struct au_br_hfsnotify *hfsn; ++ ++ hfsn = br->br_hfsn; ++ if (hfsn) { ++ lockdep_off(); ++ fsnotify_put_group(hfsn->hfsn_group); ++ lockdep_on(); ++ } ++} ++ ++static int au_hfsn_init_br(struct au_branch *br, int perm) ++{ ++ int err; ++ struct fsnotify_group *group; ++ struct au_br_hfsnotify *hfsn; ++ ++ err = 0; ++ br->br_hfsn = NULL; ++ if (!au_br_hnotifyable(perm)) ++ goto out; ++ ++ err = -ENOMEM; ++ hfsn = kmalloc(sizeof(*hfsn), GFP_NOFS); ++ if (unlikely(!hfsn)) ++ goto out; ++ ++ err = 0; ++ group = fsnotify_alloc_group(&au_hfsn_ops); ++ if (IS_ERR(group)) { ++ err = PTR_ERR(group); ++ pr_err("fsnotify_alloc_group() failed, %d\n", err); ++ goto out_hfsn; ++ } ++ ++ group->private = hfsn; ++ hfsn->hfsn_group = group; ++ br->br_hfsn = hfsn; ++ goto out; /* success */ ++ ++out_hfsn: ++ au_kfree_try_rcu(hfsn); ++out: ++ return err; ++} ++ ++static int au_hfsn_reset_br(unsigned int udba, struct au_branch *br, int perm) ++{ ++ int err; ++ ++ err = 0; ++ if (!br->br_hfsn) ++ err = au_hfsn_init_br(br, perm); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_hfsn_fin(void) ++{ ++ AuDbg("au_hfsn_ifree %lld\n", (long long)atomic64_read(&au_hfsn_ifree)); ++ wait_event(au_hfsn_wq, !atomic64_read(&au_hfsn_ifree)); ++} ++ ++const struct au_hnotify_op au_hnotify_op = { ++ .ctl = au_hfsn_ctl, ++ .alloc = au_hfsn_alloc, ++ .free = au_hfsn_free, ++ ++ .fin = au_hfsn_fin, ++ ++ .reset_br = au_hfsn_reset_br, ++ .fin_br = au_hfsn_fin_br, ++ .init_br = au_hfsn_init_br ++}; +diff -Nurp linux-5.15.37/fs/aufs/hfsplus.c linux-5.15.37-aufs/fs/aufs/hfsplus.c +--- linux-5.15.37/fs/aufs/hfsplus.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/hfsplus.c 2022-04-08 20:22:30.613616524 +0300 +@@ -0,0 +1,47 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2010-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * special support for filesystems which acquires an inode mutex ++ * at final closing a file, eg, hfsplus. ++ * ++ * This trick is very simple and stupid, just to open the file before really ++ * necessary open to tell hfsplus that this is not the final closing. ++ * The caller should call au_h_open_pre() after acquiring the inode mutex, ++ * and au_h_open_post() after releasing it. ++ */ ++ ++#include "aufs.h" ++ ++struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex, ++ int force_wr) ++{ ++ struct file *h_file; ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ AuDebugOn(!h_dentry); ++ AuDebugOn(d_is_negative(h_dentry)); ++ ++ h_file = NULL; ++ if (au_test_hfsplus(h_dentry->d_sb) ++ && d_is_reg(h_dentry)) ++ h_file = au_h_open(dentry, bindex, ++ O_RDONLY | O_NOATIME | O_LARGEFILE, ++ /*file*/NULL, force_wr); ++ return h_file; ++} ++ ++void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex, ++ struct file *h_file) ++{ ++ struct au_branch *br; ++ ++ if (h_file) { ++ fput(h_file); ++ br = au_sbr(dentry->d_sb, bindex); ++ au_lcnt_dec(&br->br_nfiles); ++ } ++} +diff -Nurp linux-5.15.37/fs/aufs/hnotify.c linux-5.15.37-aufs/fs/aufs/hnotify.c +--- linux-5.15.37/fs/aufs/hnotify.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/hnotify.c 2022-04-08 20:22:30.613616524 +0300 +@@ -0,0 +1,702 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * abstraction to notify the direct changes on lower directories ++ */ ++ ++/* #include */ ++#include "aufs.h" ++ ++int au_hn_alloc(struct au_hinode *hinode, struct inode *inode) ++{ ++ int err; ++ struct au_hnotify *hn; ++ ++ err = -ENOMEM; ++ hn = au_cache_alloc_hnotify(); ++ if (hn) { ++ hn->hn_aufs_inode = inode; ++ hinode->hi_notify = hn; ++ err = au_hnotify_op.alloc(hinode); ++ AuTraceErr(err); ++ if (unlikely(err)) { ++ hinode->hi_notify = NULL; ++ au_cache_free_hnotify(hn); ++ /* ++ * The upper dir was removed by udba, but the same named ++ * dir left. In this case, aufs assigns a new inode ++ * number and set the monitor again. ++ * For the lower dir, the old monitor is still left. ++ */ ++ if (err == -EEXIST) ++ err = 0; ++ } ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_hn_free(struct au_hinode *hinode) ++{ ++ struct au_hnotify *hn; ++ ++ hn = hinode->hi_notify; ++ if (hn) { ++ hinode->hi_notify = NULL; ++ if (au_hnotify_op.free(hinode, hn)) ++ au_cache_free_hnotify(hn); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_hn_ctl(struct au_hinode *hinode, int do_set) ++{ ++ if (hinode->hi_notify) ++ au_hnotify_op.ctl(hinode, do_set); ++} ++ ++void au_hn_reset(struct inode *inode, unsigned int flags) ++{ ++ aufs_bindex_t bindex, bbot; ++ struct inode *hi; ++ struct dentry *iwhdentry; ++ ++ bbot = au_ibbot(inode); ++ for (bindex = au_ibtop(inode); bindex <= bbot; bindex++) { ++ hi = au_h_iptr(inode, bindex); ++ if (!hi) ++ continue; ++ ++ /* inode_lock_nested(hi, AuLsc_I_CHILD); */ ++ iwhdentry = au_hi_wh(inode, bindex); ++ if (iwhdentry) ++ dget(iwhdentry); ++ au_igrab(hi); ++ au_set_h_iptr(inode, bindex, NULL, 0); ++ au_set_h_iptr(inode, bindex, au_igrab(hi), ++ flags & ~AuHi_XINO); ++ iput(hi); ++ dput(iwhdentry); ++ /* inode_unlock(hi); */ ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int hn_xino(struct inode *inode, struct inode *h_inode) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot, bfound, btop; ++ struct inode *h_i; ++ ++ err = 0; ++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { ++ pr_warn("branch root dir was changed\n"); ++ goto out; ++ } ++ ++ bfound = -1; ++ bbot = au_ibbot(inode); ++ btop = au_ibtop(inode); ++#if 0 /* reserved for future use */ ++ if (bindex == bbot) { ++ /* keep this ino in rename case */ ++ goto out; ++ } ++#endif ++ for (bindex = btop; bindex <= bbot; bindex++) ++ if (au_h_iptr(inode, bindex) == h_inode) { ++ bfound = bindex; ++ break; ++ } ++ if (bfound < 0) ++ goto out; ++ ++ for (bindex = btop; bindex <= bbot; bindex++) { ++ h_i = au_h_iptr(inode, bindex); ++ if (!h_i) ++ continue; ++ ++ err = au_xino_write(inode->i_sb, bindex, h_i->i_ino, /*ino*/0); ++ /* ignore this error */ ++ /* bad action? */ ++ } ++ ++ /* children inode number will be broken */ ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int hn_gen_tree(struct dentry *dentry) ++{ ++ int err, i, j, ndentry; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, dentry, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ for (i = 0; i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ ndentry = dpage->ndentry; ++ for (j = 0; j < ndentry; j++) { ++ struct dentry *d; ++ ++ d = dentries[j]; ++ if (IS_ROOT(d)) ++ continue; ++ ++ au_digen_dec(d); ++ if (d_really_is_positive(d)) ++ /* todo: reset children xino? ++ cached children only? */ ++ au_iigen_dec(d_inode(d)); ++ } ++ } ++ ++out_dpages: ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++/* ++ * return 0 if processed. ++ */ ++static int hn_gen_by_inode(char *name, unsigned int nlen, struct inode *inode, ++ const unsigned int isdir) ++{ ++ int err; ++ struct dentry *d; ++ struct qstr *dname; ++ ++ err = 1; ++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { ++ pr_warn("branch root dir was changed\n"); ++ err = 0; ++ goto out; ++ } ++ ++ if (!isdir) { ++ AuDebugOn(!name); ++ au_iigen_dec(inode); ++ spin_lock(&inode->i_lock); ++ hlist_for_each_entry(d, &inode->i_dentry, d_u.d_alias) { ++ spin_lock(&d->d_lock); ++ dname = &d->d_name; ++ if (dname->len != nlen ++ && memcmp(dname->name, name, nlen)) { ++ spin_unlock(&d->d_lock); ++ continue; ++ } ++ err = 0; ++ au_digen_dec(d); ++ spin_unlock(&d->d_lock); ++ break; ++ } ++ spin_unlock(&inode->i_lock); ++ } else { ++ au_fset_si(au_sbi(inode->i_sb), FAILED_REFRESH_DIR); ++ d = d_find_any_alias(inode); ++ if (!d) { ++ au_iigen_dec(inode); ++ goto out; ++ } ++ ++ spin_lock(&d->d_lock); ++ dname = &d->d_name; ++ if (dname->len == nlen && !memcmp(dname->name, name, nlen)) { ++ spin_unlock(&d->d_lock); ++ err = hn_gen_tree(d); ++ spin_lock(&d->d_lock); ++ } ++ spin_unlock(&d->d_lock); ++ dput(d); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int hn_gen_by_name(struct dentry *dentry, const unsigned int isdir) ++{ ++ int err; ++ ++ if (IS_ROOT(dentry)) { ++ pr_warn("branch root dir was changed\n"); ++ return 0; ++ } ++ ++ err = 0; ++ if (!isdir) { ++ au_digen_dec(dentry); ++ if (d_really_is_positive(dentry)) ++ au_iigen_dec(d_inode(dentry)); ++ } else { ++ au_fset_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR); ++ if (d_really_is_positive(dentry)) ++ err = hn_gen_tree(dentry); ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* hnotify job flags */ ++#define AuHnJob_XINO0 1 ++#define AuHnJob_GEN (1 << 1) ++#define AuHnJob_DIRENT (1 << 2) ++#define AuHnJob_ISDIR (1 << 3) ++#define AuHnJob_TRYXINO0 (1 << 4) ++#define AuHnJob_MNTPNT (1 << 5) ++#define au_ftest_hnjob(flags, name) ((flags) & AuHnJob_##name) ++#define au_fset_hnjob(flags, name) \ ++ do { (flags) |= AuHnJob_##name; } while (0) ++#define au_fclr_hnjob(flags, name) \ ++ do { (flags) &= ~AuHnJob_##name; } while (0) ++ ++enum { ++ AuHn_CHILD, ++ AuHn_PARENT, ++ AuHnLast ++}; ++ ++struct au_hnotify_args { ++ struct inode *h_dir, *dir, *h_child_inode; ++ u32 mask; ++ unsigned int flags[AuHnLast]; ++ unsigned int h_child_nlen; ++ char h_child_name[]; ++}; ++ ++struct hn_job_args { ++ unsigned int flags; ++ struct inode *inode, *h_inode, *dir, *h_dir; ++ struct dentry *dentry; ++ char *h_name; ++ int h_nlen; ++}; ++ ++static int hn_job(struct hn_job_args *a) ++{ ++ const unsigned int isdir = au_ftest_hnjob(a->flags, ISDIR); ++ int e; ++ ++ /* reset xino */ ++ if (au_ftest_hnjob(a->flags, XINO0) && a->inode) ++ hn_xino(a->inode, a->h_inode); /* ignore this error */ ++ ++ if (au_ftest_hnjob(a->flags, TRYXINO0) ++ && a->inode ++ && a->h_inode) { ++ inode_lock_shared_nested(a->h_inode, AuLsc_I_CHILD); ++ if (!a->h_inode->i_nlink ++ && !(a->h_inode->i_state & I_LINKABLE)) ++ hn_xino(a->inode, a->h_inode); /* ignore this error */ ++ inode_unlock_shared(a->h_inode); ++ } ++ ++ /* make the generation obsolete */ ++ if (au_ftest_hnjob(a->flags, GEN)) { ++ e = -1; ++ if (a->inode) ++ e = hn_gen_by_inode(a->h_name, a->h_nlen, a->inode, ++ isdir); ++ if (e && a->dentry) ++ hn_gen_by_name(a->dentry, isdir); ++ /* ignore this error */ ++ } ++ ++ /* make dir entries obsolete */ ++ if (au_ftest_hnjob(a->flags, DIRENT) && a->inode) { ++ struct au_vdir *vdir; ++ ++ vdir = au_ivdir(a->inode); ++ if (vdir) ++ vdir->vd_jiffy = 0; ++ /* IMustLock(a->inode); */ ++ /* inode_inc_iversion(a->inode); */ ++ } ++ ++ /* can do nothing but warn */ ++ if (au_ftest_hnjob(a->flags, MNTPNT) ++ && a->dentry ++ && d_mountpoint(a->dentry)) ++ pr_warn("mount-point %pd is removed or renamed\n", a->dentry); ++ ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry *lookup_wlock_by_name(char *name, unsigned int nlen, ++ struct inode *dir) ++{ ++ struct dentry *dentry, *d, *parent; ++ struct qstr *dname; ++ ++ parent = d_find_any_alias(dir); ++ if (!parent) ++ return NULL; ++ ++ dentry = NULL; ++ spin_lock(&parent->d_lock); ++ list_for_each_entry(d, &parent->d_subdirs, d_child) { ++ /* AuDbg("%pd\n", d); */ ++ spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED); ++ dname = &d->d_name; ++ if (dname->len != nlen || memcmp(dname->name, name, nlen)) ++ goto cont_unlock; ++ if (au_di(d)) ++ au_digen_dec(d); ++ else ++ goto cont_unlock; ++ if (au_dcount(d) > 0) { ++ dentry = dget_dlock(d); ++ spin_unlock(&d->d_lock); ++ break; ++ } ++ ++cont_unlock: ++ spin_unlock(&d->d_lock); ++ } ++ spin_unlock(&parent->d_lock); ++ dput(parent); ++ ++ if (dentry) ++ di_write_lock_child(dentry); ++ ++ return dentry; ++} ++ ++static struct inode *lookup_wlock_by_ino(struct super_block *sb, ++ aufs_bindex_t bindex, ino_t h_ino) ++{ ++ struct inode *inode; ++ ino_t ino; ++ int err; ++ ++ inode = NULL; ++ err = au_xino_read(sb, bindex, h_ino, &ino); ++ if (!err && ino) ++ inode = ilookup(sb, ino); ++ if (!inode) ++ goto out; ++ ++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { ++ pr_warn("wrong root branch\n"); ++ iput(inode); ++ inode = NULL; ++ goto out; ++ } ++ ++ ii_write_lock_child(inode); ++ ++out: ++ return inode; ++} ++ ++static void au_hn_bh(void *_args) ++{ ++ struct au_hnotify_args *a = _args; ++ struct super_block *sb; ++ aufs_bindex_t bindex, bbot, bfound; ++ unsigned char xino, try_iput; ++ int err; ++ struct inode *inode; ++ ino_t h_ino; ++ struct hn_job_args args; ++ struct dentry *dentry; ++ struct au_sbinfo *sbinfo; ++ ++ AuDebugOn(!_args); ++ AuDebugOn(!a->h_dir); ++ AuDebugOn(!a->dir); ++ AuDebugOn(!a->mask); ++ AuDbg("mask 0x%x, i%lu, hi%lu, hci%lu\n", ++ a->mask, a->dir->i_ino, a->h_dir->i_ino, ++ a->h_child_inode ? a->h_child_inode->i_ino : 0); ++ ++ inode = NULL; ++ dentry = NULL; ++ /* ++ * do not lock a->dir->i_mutex here ++ * because of d_revalidate() may cause a deadlock. ++ */ ++ sb = a->dir->i_sb; ++ AuDebugOn(!sb); ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!sbinfo); ++ si_write_lock(sb, AuLock_NOPLMW); ++ ++ if (au_opt_test(sbinfo->si_mntflags, DIRREN)) ++ switch (a->mask & FS_EVENTS_POSS_ON_CHILD) { ++ case FS_MOVED_FROM: ++ case FS_MOVED_TO: ++ AuWarn1("DIRREN with UDBA may not work correctly " ++ "for the direct rename(2)\n"); ++ } ++ ++ ii_read_lock_parent(a->dir); ++ bfound = -1; ++ bbot = au_ibbot(a->dir); ++ for (bindex = au_ibtop(a->dir); bindex <= bbot; bindex++) ++ if (au_h_iptr(a->dir, bindex) == a->h_dir) { ++ bfound = bindex; ++ break; ++ } ++ ii_read_unlock(a->dir); ++ if (unlikely(bfound < 0)) ++ goto out; ++ ++ xino = !!au_opt_test(au_mntflags(sb), XINO); ++ h_ino = 0; ++ if (a->h_child_inode) ++ h_ino = a->h_child_inode->i_ino; ++ ++ if (a->h_child_nlen ++ && (au_ftest_hnjob(a->flags[AuHn_CHILD], GEN) ++ || au_ftest_hnjob(a->flags[AuHn_CHILD], MNTPNT))) ++ dentry = lookup_wlock_by_name(a->h_child_name, a->h_child_nlen, ++ a->dir); ++ try_iput = 0; ++ if (dentry && d_really_is_positive(dentry)) ++ inode = d_inode(dentry); ++ if (xino && !inode && h_ino ++ && (au_ftest_hnjob(a->flags[AuHn_CHILD], XINO0) ++ || au_ftest_hnjob(a->flags[AuHn_CHILD], TRYXINO0) ++ || au_ftest_hnjob(a->flags[AuHn_CHILD], GEN))) { ++ inode = lookup_wlock_by_ino(sb, bfound, h_ino); ++ try_iput = 1; ++ } ++ ++ args.flags = a->flags[AuHn_CHILD]; ++ args.dentry = dentry; ++ args.inode = inode; ++ args.h_inode = a->h_child_inode; ++ args.dir = a->dir; ++ args.h_dir = a->h_dir; ++ args.h_name = a->h_child_name; ++ args.h_nlen = a->h_child_nlen; ++ err = hn_job(&args); ++ if (dentry) { ++ if (au_di(dentry)) ++ di_write_unlock(dentry); ++ dput(dentry); ++ } ++ if (inode && try_iput) { ++ ii_write_unlock(inode); ++ iput(inode); ++ } ++ ++ ii_write_lock_parent(a->dir); ++ args.flags = a->flags[AuHn_PARENT]; ++ args.dentry = NULL; ++ args.inode = a->dir; ++ args.h_inode = a->h_dir; ++ args.dir = NULL; ++ args.h_dir = NULL; ++ args.h_name = NULL; ++ args.h_nlen = 0; ++ err = hn_job(&args); ++ ii_write_unlock(a->dir); ++ ++out: ++ iput(a->h_child_inode); ++ iput(a->h_dir); ++ iput(a->dir); ++ si_write_unlock(sb); ++ au_nwt_done(&sbinfo->si_nowait); ++ au_kfree_rcu(a); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask, ++ const struct qstr *h_child_qstr, struct inode *h_child_inode) ++{ ++ int err, len; ++ unsigned int flags[AuHnLast], f; ++ unsigned char isdir, isroot, wh; ++ struct inode *dir; ++ struct au_hnotify_args *args; ++ char *p, *h_child_name; ++ ++ err = 0; ++ AuDebugOn(!hnotify || !hnotify->hn_aufs_inode); ++ dir = igrab(hnotify->hn_aufs_inode); ++ if (!dir) ++ goto out; ++ ++ isroot = (dir->i_ino == AUFS_ROOT_INO); ++ wh = 0; ++ h_child_name = (void *)h_child_qstr->name; ++ len = h_child_qstr->len; ++ if (h_child_name) { ++ if (len > AUFS_WH_PFX_LEN ++ && !memcmp(h_child_name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { ++ h_child_name += AUFS_WH_PFX_LEN; ++ len -= AUFS_WH_PFX_LEN; ++ wh = 1; ++ } ++ } ++ ++ isdir = 0; ++ if (h_child_inode) ++ isdir = !!S_ISDIR(h_child_inode->i_mode); ++ flags[AuHn_PARENT] = AuHnJob_ISDIR; ++ flags[AuHn_CHILD] = 0; ++ if (isdir) ++ flags[AuHn_CHILD] = AuHnJob_ISDIR; ++ au_fset_hnjob(flags[AuHn_PARENT], DIRENT); ++ au_fset_hnjob(flags[AuHn_CHILD], GEN); ++ switch (mask & ALL_FSNOTIFY_DIRENT_EVENTS) { ++ case FS_MOVED_FROM: ++ case FS_MOVED_TO: ++ au_fset_hnjob(flags[AuHn_CHILD], XINO0); ++ au_fset_hnjob(flags[AuHn_CHILD], MNTPNT); ++ fallthrough; ++ case FS_CREATE: ++ AuDebugOn(!h_child_name); ++ break; ++ ++ case FS_DELETE: ++ /* ++ * aufs never be able to get this child inode. ++ * revalidation should be in d_revalidate() ++ * by checking i_nlink, i_generation or d_unhashed(). ++ */ ++ AuDebugOn(!h_child_name); ++ au_fset_hnjob(flags[AuHn_CHILD], TRYXINO0); ++ au_fset_hnjob(flags[AuHn_CHILD], MNTPNT); ++ break; ++ ++ default: ++ AuDebugOn(1); ++ } ++ ++ if (wh) ++ h_child_inode = NULL; ++ ++ err = -ENOMEM; ++ /* iput() and kfree() will be called in au_hnotify() */ ++ args = kmalloc(sizeof(*args) + len + 1, GFP_NOFS); ++ if (unlikely(!args)) { ++ AuErr1("no memory\n"); ++ iput(dir); ++ goto out; ++ } ++ args->flags[AuHn_PARENT] = flags[AuHn_PARENT]; ++ args->flags[AuHn_CHILD] = flags[AuHn_CHILD]; ++ args->mask = mask; ++ args->dir = dir; ++ args->h_dir = igrab(h_dir); ++ if (h_child_inode) ++ h_child_inode = igrab(h_child_inode); /* can be NULL */ ++ args->h_child_inode = h_child_inode; ++ args->h_child_nlen = len; ++ if (len) { ++ p = (void *)args; ++ p += sizeof(*args); ++ memcpy(p, h_child_name, len); ++ p[len] = 0; ++ } ++ ++ /* NFS fires the event for silly-renamed one from kworker */ ++ f = 0; ++ if (!dir->i_nlink ++ || (au_test_nfs(h_dir->i_sb) && (mask & FS_DELETE))) ++ f = AuWkq_NEST; ++ err = au_wkq_nowait(au_hn_bh, args, dir->i_sb, f); ++ if (unlikely(err)) { ++ pr_err("wkq %d\n", err); ++ iput(args->h_child_inode); ++ iput(args->h_dir); ++ iput(args->dir); ++ au_kfree_rcu(args); ++ } ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_hnotify_reset_br(unsigned int udba, struct au_branch *br, int perm) ++{ ++ int err; ++ ++ AuDebugOn(!(udba & AuOptMask_UDBA)); ++ ++ err = 0; ++ if (au_hnotify_op.reset_br) ++ err = au_hnotify_op.reset_br(udba, br, perm); ++ ++ return err; ++} ++ ++int au_hnotify_init_br(struct au_branch *br, int perm) ++{ ++ int err; ++ ++ err = 0; ++ if (au_hnotify_op.init_br) ++ err = au_hnotify_op.init_br(br, perm); ++ ++ return err; ++} ++ ++void au_hnotify_fin_br(struct au_branch *br) ++{ ++ if (au_hnotify_op.fin_br) ++ au_hnotify_op.fin_br(br); ++} ++ ++static void au_hn_destroy_cache(void) ++{ ++ kmem_cache_destroy(au_cache[AuCache_HNOTIFY]); ++ au_cache[AuCache_HNOTIFY] = NULL; ++} ++ ++int __init au_hnotify_init(void) ++{ ++ int err; ++ ++ err = -ENOMEM; ++ au_cache[AuCache_HNOTIFY] = AuCache(au_hnotify); ++ if (au_cache[AuCache_HNOTIFY]) { ++ err = 0; ++ if (au_hnotify_op.init) ++ err = au_hnotify_op.init(); ++ if (unlikely(err)) ++ au_hn_destroy_cache(); ++ } ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_hnotify_fin(void) ++{ ++ if (au_hnotify_op.fin) ++ au_hnotify_op.fin(); ++ ++ /* cf. au_cache_fin() */ ++ if (au_cache[AuCache_HNOTIFY]) ++ au_hn_destroy_cache(); ++} +diff -Nurp linux-5.15.37/fs/aufs/iinfo.c linux-5.15.37-aufs/fs/aufs/iinfo.c +--- linux-5.15.37/fs/aufs/iinfo.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/iinfo.c 2022-04-08 20:22:30.614616573 +0300 +@@ -0,0 +1,273 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode private data ++ */ ++ ++#include "aufs.h" ++ ++struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex) ++{ ++ struct inode *h_inode; ++ struct au_hinode *hinode; ++ ++ IiMustAnyLock(inode); ++ ++ hinode = au_hinode(au_ii(inode), bindex); ++ h_inode = hinode->hi_inode; ++ AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0); ++ return h_inode; ++} ++ ++/* todo: hard/soft set? */ ++void au_hiput(struct au_hinode *hinode) ++{ ++ au_hn_free(hinode); ++ dput(hinode->hi_whdentry); ++ iput(hinode->hi_inode); ++} ++ ++unsigned int au_hi_flags(struct inode *inode, int isdir) ++{ ++ unsigned int flags; ++ const unsigned int mnt_flags = au_mntflags(inode->i_sb); ++ ++ flags = 0; ++ if (au_opt_test(mnt_flags, XINO)) ++ au_fset_hi(flags, XINO); ++ if (isdir && au_opt_test(mnt_flags, UDBA_HNOTIFY)) ++ au_fset_hi(flags, HNOTIFY); ++ return flags; ++} ++ ++void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode, unsigned int flags) ++{ ++ struct au_hinode *hinode; ++ struct inode *hi; ++ struct au_iinfo *iinfo = au_ii(inode); ++ ++ IiMustWriteLock(inode); ++ ++ hinode = au_hinode(iinfo, bindex); ++ hi = hinode->hi_inode; ++ AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0); ++ ++ if (hi) ++ au_hiput(hinode); ++ hinode->hi_inode = h_inode; ++ if (h_inode) { ++ int err; ++ struct super_block *sb = inode->i_sb; ++ struct au_branch *br; ++ ++ AuDebugOn(inode->i_mode ++ && (h_inode->i_mode & S_IFMT) ++ != (inode->i_mode & S_IFMT)); ++ if (bindex == iinfo->ii_btop) ++ au_cpup_igen(inode, h_inode); ++ br = au_sbr(sb, bindex); ++ hinode->hi_id = br->br_id; ++ if (au_ftest_hi(flags, XINO)) { ++ err = au_xino_write(sb, bindex, h_inode->i_ino, ++ inode->i_ino); ++ if (unlikely(err)) ++ AuIOErr1("failed au_xino_write() %d\n", err); ++ } ++ ++ if (au_ftest_hi(flags, HNOTIFY) ++ && au_br_hnotifyable(br->br_perm)) { ++ err = au_hn_alloc(hinode, inode); ++ if (unlikely(err)) ++ AuIOErr1("au_hn_alloc() %d\n", err); ++ } ++ } ++} ++ ++void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_wh) ++{ ++ struct au_hinode *hinode; ++ ++ IiMustWriteLock(inode); ++ ++ hinode = au_hinode(au_ii(inode), bindex); ++ AuDebugOn(hinode->hi_whdentry); ++ hinode->hi_whdentry = h_wh; ++} ++ ++void au_update_iigen(struct inode *inode, int half) ++{ ++ struct au_iinfo *iinfo; ++ struct au_iigen *iigen; ++ unsigned int sigen; ++ ++ sigen = au_sigen(inode->i_sb); ++ iinfo = au_ii(inode); ++ iigen = &iinfo->ii_generation; ++ spin_lock(&iigen->ig_spin); ++ iigen->ig_generation = sigen; ++ if (half) ++ au_ig_fset(iigen->ig_flags, HALF_REFRESHED); ++ else ++ au_ig_fclr(iigen->ig_flags, HALF_REFRESHED); ++ spin_unlock(&iigen->ig_spin); ++} ++ ++/* it may be called at remount time, too */ ++void au_update_ibrange(struct inode *inode, int do_put_zero) ++{ ++ struct au_iinfo *iinfo; ++ aufs_bindex_t bindex, bbot; ++ ++ AuDebugOn(au_is_bad_inode(inode)); ++ IiMustWriteLock(inode); ++ ++ iinfo = au_ii(inode); ++ if (do_put_zero && iinfo->ii_btop >= 0) { ++ for (bindex = iinfo->ii_btop; bindex <= iinfo->ii_bbot; ++ bindex++) { ++ struct inode *h_i; ++ ++ h_i = au_hinode(iinfo, bindex)->hi_inode; ++ if (h_i ++ && !h_i->i_nlink ++ && !(h_i->i_state & I_LINKABLE)) ++ au_set_h_iptr(inode, bindex, NULL, 0); ++ } ++ } ++ ++ iinfo->ii_btop = -1; ++ iinfo->ii_bbot = -1; ++ bbot = au_sbbot(inode->i_sb); ++ for (bindex = 0; bindex <= bbot; bindex++) ++ if (au_hinode(iinfo, bindex)->hi_inode) { ++ iinfo->ii_btop = bindex; ++ break; ++ } ++ if (iinfo->ii_btop >= 0) ++ for (bindex = bbot; bindex >= iinfo->ii_btop; bindex--) ++ if (au_hinode(iinfo, bindex)->hi_inode) { ++ iinfo->ii_bbot = bindex; ++ break; ++ } ++ AuDebugOn(iinfo->ii_btop > iinfo->ii_bbot); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_icntnr_init_once(void *_c) ++{ ++ struct au_icntnr *c = _c; ++ struct au_iinfo *iinfo = &c->iinfo; ++ ++ spin_lock_init(&iinfo->ii_generation.ig_spin); ++ au_rw_init(&iinfo->ii_rwsem); ++ inode_init_once(&c->vfs_inode); ++} ++ ++void au_hinode_init(struct au_hinode *hinode) ++{ ++ hinode->hi_inode = NULL; ++ hinode->hi_id = -1; ++ au_hn_init(hinode); ++ hinode->hi_whdentry = NULL; ++} ++ ++int au_iinfo_init(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ struct super_block *sb; ++ struct au_hinode *hi; ++ int nbr, i; ++ ++ sb = inode->i_sb; ++ iinfo = &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); ++ nbr = au_sbbot(sb) + 1; ++ if (unlikely(nbr <= 0)) ++ nbr = 1; ++ hi = kmalloc_array(nbr, sizeof(*iinfo->ii_hinode), GFP_NOFS); ++ if (hi) { ++ au_lcnt_inc(&au_sbi(sb)->si_ninodes); ++ ++ iinfo->ii_hinode = hi; ++ for (i = 0; i < nbr; i++, hi++) ++ au_hinode_init(hi); ++ ++ iinfo->ii_generation.ig_generation = au_sigen(sb); ++ iinfo->ii_btop = -1; ++ iinfo->ii_bbot = -1; ++ iinfo->ii_vdir = NULL; ++ return 0; ++ } ++ return -ENOMEM; ++} ++ ++int au_hinode_realloc(struct au_iinfo *iinfo, int nbr, int may_shrink) ++{ ++ int err, i; ++ struct au_hinode *hip; ++ ++ AuRwMustWriteLock(&iinfo->ii_rwsem); ++ ++ err = -ENOMEM; ++ hip = au_krealloc(iinfo->ii_hinode, sizeof(*hip) * nbr, GFP_NOFS, ++ may_shrink); ++ if (hip) { ++ iinfo->ii_hinode = hip; ++ i = iinfo->ii_bbot + 1; ++ hip += i; ++ for (; i < nbr; i++, hip++) ++ au_hinode_init(hip); ++ err = 0; ++ } ++ ++ return err; ++} ++ ++void au_iinfo_fin(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ struct au_hinode *hi; ++ struct super_block *sb; ++ aufs_bindex_t bindex, bbot; ++ const unsigned char unlinked = !inode->i_nlink; ++ ++ AuDebugOn(au_is_bad_inode(inode)); ++ ++ sb = inode->i_sb; ++ au_lcnt_dec(&au_sbi(sb)->si_ninodes); ++ if (si_pid_test(sb)) ++ au_xino_delete_inode(inode, unlinked); ++ else { ++ /* ++ * it is safe to hide the dependency between sbinfo and ++ * sb->s_umount. ++ */ ++ lockdep_off(); ++ si_noflush_read_lock(sb); ++ au_xino_delete_inode(inode, unlinked); ++ si_read_unlock(sb); ++ lockdep_on(); ++ } ++ ++ iinfo = au_ii(inode); ++ if (iinfo->ii_vdir) ++ au_vdir_free(iinfo->ii_vdir); ++ ++ bindex = iinfo->ii_btop; ++ if (bindex >= 0) { ++ hi = au_hinode(iinfo, bindex); ++ bbot = iinfo->ii_bbot; ++ while (bindex++ <= bbot) { ++ if (hi->hi_inode) ++ au_hiput(hi); ++ hi++; ++ } ++ } ++ au_kfree_rcu(iinfo->ii_hinode); ++ AuRwDestroy(&iinfo->ii_rwsem); ++} +diff -Nurp linux-5.15.37/fs/aufs/inode.c linux-5.15.37-aufs/fs/aufs/inode.c +--- linux-5.15.37/fs/aufs/inode.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/inode.c 2022-04-08 20:22:30.614616573 +0300 +@@ -0,0 +1,518 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode functions ++ */ ++ ++#include ++#include "aufs.h" ++ ++struct inode *au_igrab(struct inode *inode) ++{ ++ if (inode) { ++ AuDebugOn(!atomic_read(&inode->i_count)); ++ ihold(inode); ++ } ++ return inode; ++} ++ ++static void au_refresh_hinode_attr(struct inode *inode, int do_version) ++{ ++ au_cpup_attr_all(inode, /*force*/0); ++ au_update_iigen(inode, /*half*/1); ++ if (do_version) ++ inode_inc_iversion(inode); ++} ++ ++static int au_ii_refresh(struct inode *inode, int *update) ++{ ++ int err, e, nbr; ++ umode_t type; ++ aufs_bindex_t bindex, new_bindex; ++ struct super_block *sb; ++ struct au_iinfo *iinfo; ++ struct au_hinode *p, *q, tmp; ++ ++ AuDebugOn(au_is_bad_inode(inode)); ++ IiMustWriteLock(inode); ++ ++ *update = 0; ++ sb = inode->i_sb; ++ nbr = au_sbbot(sb) + 1; ++ type = inode->i_mode & S_IFMT; ++ iinfo = au_ii(inode); ++ err = au_hinode_realloc(iinfo, nbr, /*may_shrink*/0); ++ if (unlikely(err)) ++ goto out; ++ ++ AuDebugOn(iinfo->ii_btop < 0); ++ p = au_hinode(iinfo, iinfo->ii_btop); ++ for (bindex = iinfo->ii_btop; bindex <= iinfo->ii_bbot; ++ bindex++, p++) { ++ if (!p->hi_inode) ++ continue; ++ ++ AuDebugOn(type != (p->hi_inode->i_mode & S_IFMT)); ++ new_bindex = au_br_index(sb, p->hi_id); ++ if (new_bindex == bindex) ++ continue; ++ ++ if (new_bindex < 0) { ++ *update = 1; ++ au_hiput(p); ++ p->hi_inode = NULL; ++ continue; ++ } ++ ++ if (new_bindex < iinfo->ii_btop) ++ iinfo->ii_btop = new_bindex; ++ if (iinfo->ii_bbot < new_bindex) ++ iinfo->ii_bbot = new_bindex; ++ /* swap two lower inode, and loop again */ ++ q = au_hinode(iinfo, new_bindex); ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hi_inode) { ++ bindex--; ++ p--; ++ } ++ } ++ au_update_ibrange(inode, /*do_put_zero*/0); ++ au_hinode_realloc(iinfo, nbr, /*may_shrink*/1); /* harmless if err */ ++ e = au_dy_irefresh(inode); ++ if (unlikely(e && !err)) ++ err = e; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_refresh_iop(struct inode *inode, int force_getattr) ++{ ++ int type; ++ struct au_sbinfo *sbi = au_sbi(inode->i_sb); ++ const struct inode_operations *iop ++ = force_getattr ? aufs_iop : sbi->si_iop_array; ++ ++ if (inode->i_op == iop) ++ return; ++ ++ switch (inode->i_mode & S_IFMT) { ++ case S_IFDIR: ++ type = AuIop_DIR; ++ break; ++ case S_IFLNK: ++ type = AuIop_SYMLINK; ++ break; ++ default: ++ type = AuIop_OTHER; ++ break; ++ } ++ ++ inode->i_op = iop + type; ++ /* unnecessary smp_wmb() */ ++} ++ ++int au_refresh_hinode_self(struct inode *inode) ++{ ++ int err, update; ++ ++ err = au_ii_refresh(inode, &update); ++ if (!err) ++ au_refresh_hinode_attr(inode, update && S_ISDIR(inode->i_mode)); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_refresh_hinode(struct inode *inode, struct dentry *dentry) ++{ ++ int err, e, update; ++ unsigned int flags; ++ umode_t mode; ++ aufs_bindex_t bindex, bbot; ++ unsigned char isdir; ++ struct au_hinode *p; ++ struct au_iinfo *iinfo; ++ ++ err = au_ii_refresh(inode, &update); ++ if (unlikely(err)) ++ goto out; ++ ++ update = 0; ++ iinfo = au_ii(inode); ++ p = au_hinode(iinfo, iinfo->ii_btop); ++ mode = (inode->i_mode & S_IFMT); ++ isdir = S_ISDIR(mode); ++ flags = au_hi_flags(inode, isdir); ++ bbot = au_dbbot(dentry); ++ for (bindex = au_dbtop(dentry); bindex <= bbot; bindex++) { ++ struct inode *h_i, *h_inode; ++ struct dentry *h_d; ++ ++ h_d = au_h_dptr(dentry, bindex); ++ if (!h_d || d_is_negative(h_d)) ++ continue; ++ ++ h_inode = d_inode(h_d); ++ AuDebugOn(mode != (h_inode->i_mode & S_IFMT)); ++ if (iinfo->ii_btop <= bindex && bindex <= iinfo->ii_bbot) { ++ h_i = au_h_iptr(inode, bindex); ++ if (h_i) { ++ if (h_i == h_inode) ++ continue; ++ err = -EIO; ++ break; ++ } ++ } ++ if (bindex < iinfo->ii_btop) ++ iinfo->ii_btop = bindex; ++ if (iinfo->ii_bbot < bindex) ++ iinfo->ii_bbot = bindex; ++ au_set_h_iptr(inode, bindex, au_igrab(h_inode), flags); ++ update = 1; ++ } ++ au_update_ibrange(inode, /*do_put_zero*/0); ++ e = au_dy_irefresh(inode); ++ if (unlikely(e && !err)) ++ err = e; ++ if (!err) ++ au_refresh_hinode_attr(inode, update && isdir); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int set_inode(struct inode *inode, struct dentry *dentry) ++{ ++ int err; ++ unsigned int flags; ++ umode_t mode; ++ aufs_bindex_t bindex, btop, btail; ++ unsigned char isdir; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct au_iinfo *iinfo; ++ const struct inode_operations *iop; ++ ++ IiMustWriteLock(inode); ++ ++ err = 0; ++ isdir = 0; ++ iop = au_sbi(inode->i_sb)->si_iop_array; ++ btop = au_dbtop(dentry); ++ h_dentry = au_h_dptr(dentry, btop); ++ h_inode = d_inode(h_dentry); ++ mode = h_inode->i_mode; ++ switch (mode & S_IFMT) { ++ case S_IFREG: ++ btail = au_dbtail(dentry); ++ inode->i_op = iop + AuIop_OTHER; ++ inode->i_fop = &aufs_file_fop; ++ err = au_dy_iaop(inode, btop, h_inode); ++ if (unlikely(err)) ++ goto out; ++ break; ++ case S_IFDIR: ++ isdir = 1; ++ btail = au_dbtaildir(dentry); ++ inode->i_op = iop + AuIop_DIR; ++ inode->i_fop = &aufs_dir_fop; ++ break; ++ case S_IFLNK: ++ btail = au_dbtail(dentry); ++ inode->i_op = iop + AuIop_SYMLINK; ++ break; ++ case S_IFBLK: ++ case S_IFCHR: ++ case S_IFIFO: ++ case S_IFSOCK: ++ btail = au_dbtail(dentry); ++ inode->i_op = iop + AuIop_OTHER; ++ init_special_inode(inode, mode, h_inode->i_rdev); ++ break; ++ default: ++ AuIOErr("Unknown file type 0%o\n", mode); ++ err = -EIO; ++ goto out; ++ } ++ ++ /* do not set hnotify for whiteouted dirs (SHWH mode) */ ++ flags = au_hi_flags(inode, isdir); ++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH) ++ && au_ftest_hi(flags, HNOTIFY) ++ && dentry->d_name.len > AUFS_WH_PFX_LEN ++ && !memcmp(dentry->d_name.name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) ++ au_fclr_hi(flags, HNOTIFY); ++ iinfo = au_ii(inode); ++ iinfo->ii_btop = btop; ++ iinfo->ii_bbot = btail; ++ for (bindex = btop; bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry) ++ au_set_h_iptr(inode, bindex, ++ au_igrab(d_inode(h_dentry)), flags); ++ } ++ au_cpup_attr_all(inode, /*force*/1); ++ /* ++ * to force calling aufs_get_acl() every time, ++ * do not call cache_no_acl() for aufs inode. ++ */ ++ ++out: ++ return err; ++} ++ ++/* ++ * successful returns with iinfo write_locked ++ * minus: errno ++ * zero: success, matched ++ * plus: no error, but unmatched ++ */ ++static int reval_inode(struct inode *inode, struct dentry *dentry) ++{ ++ int err; ++ unsigned int gen, igflags; ++ aufs_bindex_t bindex, bbot; ++ struct inode *h_inode, *h_dinode; ++ struct dentry *h_dentry; ++ ++ /* ++ * before this function, if aufs got any iinfo lock, it must be only ++ * one, the parent dir. ++ * it can happen by UDBA and the obsoleted inode number. ++ */ ++ err = -EIO; ++ if (unlikely(inode->i_ino == parent_ino(dentry))) ++ goto out; ++ ++ err = 1; ++ ii_write_lock_new_child(inode); ++ h_dentry = au_h_dptr(dentry, au_dbtop(dentry)); ++ h_dinode = d_inode(h_dentry); ++ bbot = au_ibbot(inode); ++ for (bindex = au_ibtop(inode); bindex <= bbot; bindex++) { ++ h_inode = au_h_iptr(inode, bindex); ++ if (!h_inode || h_inode != h_dinode) ++ continue; ++ ++ err = 0; ++ gen = au_iigen(inode, &igflags); ++ if (gen == au_digen(dentry) ++ && !au_ig_ftest(igflags, HALF_REFRESHED)) ++ break; ++ ++ /* fully refresh inode using dentry */ ++ err = au_refresh_hinode(inode, dentry); ++ if (!err) ++ au_update_iigen(inode, /*half*/0); ++ break; ++ } ++ ++ if (unlikely(err)) ++ ii_write_unlock(inode); ++out: ++ return err; ++} ++ ++int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ unsigned int d_type, ino_t *ino) ++{ ++ int err, idx; ++ const int isnondir = d_type != DT_DIR; ++ ++ /* prevent hardlinked inode number from race condition */ ++ if (isnondir) { ++ err = au_xinondir_enter(sb, bindex, h_ino, &idx); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ err = au_xino_read(sb, bindex, h_ino, ino); ++ if (unlikely(err)) ++ goto out_xinondir; ++ ++ if (!*ino) { ++ err = -EIO; ++ *ino = au_xino_new_ino(sb); ++ if (unlikely(!*ino)) ++ goto out_xinondir; ++ err = au_xino_write(sb, bindex, h_ino, *ino); ++ if (unlikely(err)) ++ goto out_xinondir; ++ } ++ ++out_xinondir: ++ if (isnondir && idx >= 0) ++ au_xinondir_leave(sb, bindex, h_ino, idx); ++out: ++ return err; ++} ++ ++/* successful returns with iinfo write_locked */ ++/* todo: return with unlocked? */ ++struct inode *au_new_inode(struct dentry *dentry, int must_new) ++{ ++ struct inode *inode, *h_inode; ++ struct dentry *h_dentry; ++ struct super_block *sb; ++ ino_t h_ino, ino; ++ int err, idx, hlinked; ++ aufs_bindex_t btop; ++ ++ sb = dentry->d_sb; ++ btop = au_dbtop(dentry); ++ h_dentry = au_h_dptr(dentry, btop); ++ h_inode = d_inode(h_dentry); ++ h_ino = h_inode->i_ino; ++ hlinked = !d_is_dir(h_dentry) && h_inode->i_nlink > 1; ++ ++new_ino: ++ /* ++ * stop 'race'-ing between hardlinks under different ++ * parents. ++ */ ++ if (hlinked) { ++ err = au_xinondir_enter(sb, btop, h_ino, &idx); ++ inode = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ err = au_xino_read(sb, btop, h_ino, &ino); ++ inode = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_xinondir; ++ ++ if (!ino) { ++ ino = au_xino_new_ino(sb); ++ if (unlikely(!ino)) { ++ inode = ERR_PTR(-EIO); ++ goto out_xinondir; ++ } ++ } ++ ++ AuDbg("i%lu\n", (unsigned long)ino); ++ inode = au_iget_locked(sb, ino); ++ err = PTR_ERR(inode); ++ if (IS_ERR(inode)) ++ goto out_xinondir; ++ ++ AuDbg("%lx, new %d\n", inode->i_state, !!(inode->i_state & I_NEW)); ++ if (inode->i_state & I_NEW) { ++ ii_write_lock_new_child(inode); ++ err = set_inode(inode, dentry); ++ if (!err) { ++ unlock_new_inode(inode); ++ goto out_xinondir; /* success */ ++ } ++ ++ /* ++ * iget_failed() calls iput(), but we need to call ++ * ii_write_unlock() after iget_failed(). so dirty hack for ++ * i_count. ++ */ ++ atomic_inc(&inode->i_count); ++ iget_failed(inode); ++ ii_write_unlock(inode); ++ au_xino_write(sb, btop, h_ino, /*ino*/0); ++ /* ignore this error */ ++ goto out_iput; ++ } else if (!must_new && !IS_DEADDIR(inode) && inode->i_nlink) { ++ /* ++ * horrible race condition between lookup, readdir and copyup ++ * (or something). ++ */ ++ if (hlinked && idx >= 0) ++ au_xinondir_leave(sb, btop, h_ino, idx); ++ err = reval_inode(inode, dentry); ++ if (unlikely(err < 0)) { ++ hlinked = 0; ++ goto out_iput; ++ } ++ if (!err) ++ goto out; /* success */ ++ else if (hlinked && idx >= 0) { ++ err = au_xinondir_enter(sb, btop, h_ino, &idx); ++ if (unlikely(err)) { ++ iput(inode); ++ inode = ERR_PTR(err); ++ goto out; ++ } ++ } ++ } ++ ++ if (unlikely(au_test_fs_unique_ino(h_inode))) ++ AuWarn1("Warning: Un-notified UDBA or repeatedly renamed dir," ++ " b%d, %s, %pd, hi%lu, i%lu.\n", ++ btop, au_sbtype(h_dentry->d_sb), dentry, ++ (unsigned long)h_ino, (unsigned long)ino); ++ ino = 0; ++ err = au_xino_write(sb, btop, h_ino, /*ino*/0); ++ if (!err) { ++ iput(inode); ++ if (hlinked && idx >= 0) ++ au_xinondir_leave(sb, btop, h_ino, idx); ++ goto new_ino; ++ } ++ ++out_iput: ++ iput(inode); ++ inode = ERR_PTR(err); ++out_xinondir: ++ if (hlinked && idx >= 0) ++ au_xinondir_leave(sb, btop, h_ino, idx); ++out: ++ return inode; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_test_ro(struct super_block *sb, aufs_bindex_t bindex, ++ struct inode *inode) ++{ ++ int err; ++ struct inode *hi; ++ ++ err = au_br_rdonly(au_sbr(sb, bindex)); ++ ++ /* pseudo-link after flushed may happen out of bounds */ ++ if (!err ++ && inode ++ && au_ibtop(inode) <= bindex ++ && bindex <= au_ibbot(inode)) { ++ /* ++ * permission check is unnecessary since vfsub routine ++ * will be called later ++ */ ++ hi = au_h_iptr(inode, bindex); ++ if (hi) ++ err = IS_IMMUTABLE(hi) ? -EROFS : 0; ++ } ++ ++ return err; ++} ++ ++int au_test_h_perm(struct user_namespace *h_userns, struct inode *h_inode, ++ int mask) ++{ ++ if (uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) ++ return 0; ++ return inode_permission(h_userns, h_inode, mask); ++} ++ ++int au_test_h_perm_sio(struct user_namespace *h_userns, struct inode *h_inode, ++ int mask) ++{ ++ if (au_test_nfs(h_inode->i_sb) ++ && (mask & MAY_WRITE) ++ && S_ISDIR(h_inode->i_mode)) ++ mask |= MAY_READ; /* force permission check */ ++ return au_test_h_perm(h_userns, h_inode, mask); ++} +diff -Nurp linux-5.15.37/fs/aufs/inode.h linux-5.15.37-aufs/fs/aufs/inode.h +--- linux-5.15.37/fs/aufs/inode.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/inode.h 2022-04-08 20:22:30.614616573 +0300 +@@ -0,0 +1,692 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode operations ++ */ ++ ++#ifndef __AUFS_INODE_H__ ++#define __AUFS_INODE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "rwsem.h" ++ ++struct vfsmount; ++ ++struct au_hnotify { ++#ifdef CONFIG_AUFS_HNOTIFY ++#ifdef CONFIG_AUFS_HFSNOTIFY ++ /* never use fsnotify_add_vfsmount_mark() */ ++ struct fsnotify_mark hn_mark; ++#endif ++ struct inode *hn_aufs_inode; /* no get/put */ ++ struct rcu_head rcu; ++#endif ++} ____cacheline_aligned_in_smp; ++ ++struct au_hinode { ++ struct inode *hi_inode; ++ aufs_bindex_t hi_id; ++#ifdef CONFIG_AUFS_HNOTIFY ++ struct au_hnotify *hi_notify; ++#endif ++ ++ /* reference to the copied-up whiteout with get/put */ ++ struct dentry *hi_whdentry; ++}; ++ ++/* ig_flags */ ++#define AuIG_HALF_REFRESHED 1 ++#define au_ig_ftest(flags, name) ((flags) & AuIG_##name) ++#define au_ig_fset(flags, name) \ ++ do { (flags) |= AuIG_##name; } while (0) ++#define au_ig_fclr(flags, name) \ ++ do { (flags) &= ~AuIG_##name; } while (0) ++ ++struct au_iigen { ++ spinlock_t ig_spin; ++ __u32 ig_generation, ig_flags; ++}; ++ ++struct au_vdir; ++struct au_iinfo { ++ struct au_iigen ii_generation; ++ struct super_block *ii_hsb1; /* no get/put */ ++ ++ struct au_rwsem ii_rwsem; ++ aufs_bindex_t ii_btop, ii_bbot; ++ __u32 ii_higen; ++ struct au_hinode *ii_hinode; ++ struct au_vdir *ii_vdir; ++}; ++ ++struct au_icntnr { ++ struct au_iinfo iinfo; ++ struct inode vfs_inode; ++ struct hlist_bl_node plink; ++ struct rcu_head rcu; ++} ____cacheline_aligned_in_smp; ++ ++/* au_pin flags */ ++#define AuPin_DI_LOCKED 1 ++#define AuPin_MNT_WRITE (1 << 1) ++#define au_ftest_pin(flags, name) ((flags) & AuPin_##name) ++#define au_fset_pin(flags, name) \ ++ do { (flags) |= AuPin_##name; } while (0) ++#define au_fclr_pin(flags, name) \ ++ do { (flags) &= ~AuPin_##name; } while (0) ++ ++struct au_pin { ++ /* input */ ++ struct dentry *dentry; ++ unsigned int udba; ++ unsigned char lsc_di, lsc_hi, flags; ++ aufs_bindex_t bindex; ++ ++ /* output */ ++ struct dentry *parent; ++ struct au_hinode *hdir; ++ struct vfsmount *h_mnt; ++ ++ /* temporary unlock/relock for copyup */ ++ struct dentry *h_dentry, *h_parent; ++ struct au_branch *br; ++ struct task_struct *task; ++}; ++ ++void au_pin_hdir_unlock(struct au_pin *p); ++int au_pin_hdir_lock(struct au_pin *p); ++int au_pin_hdir_relock(struct au_pin *p); ++void au_pin_hdir_acquire_nest(struct au_pin *p); ++void au_pin_hdir_release(struct au_pin *p); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_iinfo *au_ii(struct inode *inode) ++{ ++ BUG_ON(is_bad_inode(inode)); ++ return &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* inode.c */ ++struct inode *au_igrab(struct inode *inode); ++void au_refresh_iop(struct inode *inode, int force_getattr); ++int au_refresh_hinode_self(struct inode *inode); ++int au_refresh_hinode(struct inode *inode, struct dentry *dentry); ++int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ unsigned int d_type, ino_t *ino); ++struct inode *au_new_inode(struct dentry *dentry, int must_new); ++int au_test_ro(struct super_block *sb, aufs_bindex_t bindex, ++ struct inode *inode); ++int au_test_h_perm(struct user_namespace *h_userns, struct inode *h_inode, ++ int mask); ++int au_test_h_perm_sio(struct user_namespace *h_userns, struct inode *h_inode, ++ int mask); ++ ++static inline int au_wh_ino(struct super_block *sb, aufs_bindex_t bindex, ++ ino_t h_ino, unsigned int d_type, ino_t *ino) ++{ ++#ifdef CONFIG_AUFS_SHWH ++ return au_ino(sb, bindex, h_ino, d_type, ino); ++#else ++ return 0; ++#endif ++} ++ ++/* i_op.c */ ++enum { ++ AuIop_SYMLINK, ++ AuIop_DIR, ++ AuIop_OTHER, ++ AuIop_Last ++}; ++extern struct inode_operations aufs_iop[AuIop_Last], /* not const */ ++ aufs_iop_nogetattr[AuIop_Last]; ++ ++/* au_wr_dir flags */ ++#define AuWrDir_ADD_ENTRY 1 ++#define AuWrDir_ISDIR (1 << 1) ++#define AuWrDir_TMPFILE (1 << 2) ++#define au_ftest_wrdir(flags, name) ((flags) & AuWrDir_##name) ++#define au_fset_wrdir(flags, name) \ ++ do { (flags) |= AuWrDir_##name; } while (0) ++#define au_fclr_wrdir(flags, name) \ ++ do { (flags) &= ~AuWrDir_##name; } while (0) ++ ++struct au_wr_dir_args { ++ aufs_bindex_t force_btgt; ++ unsigned char flags; ++}; ++int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry, ++ struct au_wr_dir_args *args); ++ ++struct dentry *au_pinned_h_parent(struct au_pin *pin); ++void au_pin_init(struct au_pin *pin, struct dentry *dentry, ++ aufs_bindex_t bindex, int lsc_di, int lsc_hi, ++ unsigned int udba, unsigned char flags); ++int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int udba, unsigned char flags) __must_check; ++int au_do_pin(struct au_pin *pin) __must_check; ++void au_unpin(struct au_pin *pin); ++int au_reval_for_attr(struct dentry *dentry, unsigned int sigen); ++ ++#define AuIcpup_DID_CPUP 1 ++#define au_ftest_icpup(flags, name) ((flags) & AuIcpup_##name) ++#define au_fset_icpup(flags, name) \ ++ do { (flags) |= AuIcpup_##name; } while (0) ++#define au_fclr_icpup(flags, name) \ ++ do { (flags) &= ~AuIcpup_##name; } while (0) ++ ++struct au_icpup_args { ++ unsigned char flags; ++ unsigned char pin_flags; ++ aufs_bindex_t btgt; ++ unsigned int udba; ++ struct au_pin pin; ++ struct path h_path; ++ struct inode *h_inode; ++}; ++ ++int au_pin_and_icpup(struct dentry *dentry, struct iattr *ia, ++ struct au_icpup_args *a); ++ ++int au_h_path_getattr(struct dentry *dentry, struct inode *inode, int force, ++ struct path *h_path, int locked); ++ ++/* i_op_add.c */ ++int au_may_add(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, int isdir); ++int aufs_mknod(struct user_namespace *userns, struct inode *dir, ++ struct dentry *dentry, umode_t mode, dev_t dev); ++int aufs_symlink(struct user_namespace *userns, struct inode *dir, ++ struct dentry *dentry, const char *symname); ++int aufs_create(struct user_namespace *userns, struct inode *dir, ++ struct dentry *dentry, umode_t mode, bool want_excl); ++struct vfsub_aopen_args; ++int au_aopen_or_create(struct inode *dir, struct dentry *dentry, ++ struct vfsub_aopen_args *args); ++int aufs_tmpfile(struct user_namespace *userns, struct inode *dir, ++ struct dentry *dentry, umode_t mode); ++int aufs_link(struct dentry *src_dentry, struct inode *dir, ++ struct dentry *dentry); ++int aufs_mkdir(struct user_namespace *userns, struct inode *dir, ++ struct dentry *dentry, umode_t mode); ++ ++/* i_op_del.c */ ++int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup); ++int au_may_del(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, int isdir); ++int aufs_unlink(struct inode *dir, struct dentry *dentry); ++int aufs_rmdir(struct inode *dir, struct dentry *dentry); ++ ++/* i_op_ren.c */ ++int au_wbr(struct dentry *dentry, aufs_bindex_t btgt); ++int aufs_rename(struct user_namespace *userns, ++ struct inode *_src_dir, struct dentry *_src_dentry, ++ struct inode *_dst_dir, struct dentry *_dst_dentry, ++ unsigned int _flags); ++ ++/* iinfo.c */ ++struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex); ++void au_hiput(struct au_hinode *hinode); ++void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_wh); ++unsigned int au_hi_flags(struct inode *inode, int isdir); ++ ++/* hinode flags */ ++#define AuHi_XINO 1 ++#define AuHi_HNOTIFY (1 << 1) ++#define au_ftest_hi(flags, name) ((flags) & AuHi_##name) ++#define au_fset_hi(flags, name) \ ++ do { (flags) |= AuHi_##name; } while (0) ++#define au_fclr_hi(flags, name) \ ++ do { (flags) &= ~AuHi_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_HNOTIFY ++#undef AuHi_HNOTIFY ++#define AuHi_HNOTIFY 0 ++#endif ++ ++void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode, unsigned int flags); ++ ++void au_update_iigen(struct inode *inode, int half); ++void au_update_ibrange(struct inode *inode, int do_put_zero); ++ ++void au_icntnr_init_once(void *_c); ++void au_hinode_init(struct au_hinode *hinode); ++int au_iinfo_init(struct inode *inode); ++void au_iinfo_fin(struct inode *inode); ++int au_hinode_realloc(struct au_iinfo *iinfo, int nbr, int may_shrink); ++ ++#ifdef CONFIG_PROC_FS ++/* plink.c */ ++int au_plink_maint(struct super_block *sb, int flags); ++struct au_sbinfo; ++void au_plink_maint_leave(struct au_sbinfo *sbinfo); ++int au_plink_maint_enter(struct super_block *sb); ++#ifdef CONFIG_AUFS_DEBUG ++void au_plink_list(struct super_block *sb); ++#else ++AuStubVoid(au_plink_list, struct super_block *sb) ++#endif ++int au_plink_test(struct inode *inode); ++struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex); ++void au_plink_append(struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_dentry); ++void au_plink_put(struct super_block *sb, int verbose); ++void au_plink_clean(struct super_block *sb, int verbose); ++void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id); ++#else ++AuStubInt0(au_plink_maint, struct super_block *sb, int flags); ++AuStubVoid(au_plink_maint_leave, struct au_sbinfo *sbinfo); ++AuStubInt0(au_plink_maint_enter, struct super_block *sb); ++AuStubVoid(au_plink_list, struct super_block *sb); ++AuStubInt0(au_plink_test, struct inode *inode); ++AuStub(struct dentry *, au_plink_lkup, return NULL, ++ struct inode *inode, aufs_bindex_t bindex); ++AuStubVoid(au_plink_append, struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_dentry); ++AuStubVoid(au_plink_put, struct super_block *sb, int verbose); ++AuStubVoid(au_plink_clean, struct super_block *sb, int verbose); ++AuStubVoid(au_plink_half_refresh, struct super_block *sb, aufs_bindex_t br_id); ++#endif /* CONFIG_PROC_FS */ ++ ++#ifdef CONFIG_AUFS_XATTR ++/* xattr.c */ ++int au_cpup_xattr(struct path *h_dst, struct path *h_src, int ignore_flags, ++ unsigned int verbose); ++ssize_t aufs_listxattr(struct dentry *dentry, char *list, size_t size); ++void au_xattr_init(struct super_block *sb); ++#else ++AuStubInt0(au_cpup_xattr, struct path *h_dst, struct path *h_src, ++ int ignore_flags, unsigned int verbose); ++AuStubVoid(au_xattr_init, struct super_block *sb); ++#endif ++ ++#ifdef CONFIG_FS_POSIX_ACL ++struct posix_acl *aufs_get_acl(struct inode *inode, int type, bool rcu); ++int aufs_set_acl(struct user_namespace *userns, struct inode *inode, ++ struct posix_acl *acl, int type); ++#endif ++ ++#if IS_ENABLED(CONFIG_AUFS_XATTR) || IS_ENABLED(CONFIG_FS_POSIX_ACL) ++enum { ++ AU_XATTR_SET, ++ AU_ACL_SET ++}; ++ ++struct au_sxattr { ++ int type; ++ union { ++ struct { ++ const char *name; ++ const void *value; ++ size_t size; ++ int flags; ++ } set; ++ struct { ++ struct posix_acl *acl; ++ int type; ++ } acl_set; ++ } u; ++}; ++ssize_t au_sxattr(struct dentry *dentry, struct inode *inode, ++ struct au_sxattr *arg); ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock subclass for iinfo */ ++enum { ++ AuLsc_II_CHILD, /* child first */ ++ AuLsc_II_CHILD2, /* rename(2), link(2), and cpup at hnotify */ ++ AuLsc_II_CHILD3, /* copyup dirs */ ++ AuLsc_II_PARENT, /* see AuLsc_I_PARENT in vfsub.h */ ++ AuLsc_II_PARENT2, ++ AuLsc_II_PARENT3, /* copyup dirs */ ++ AuLsc_II_NEW_CHILD ++}; ++ ++/* ++ * ii_read_lock_child, ii_write_lock_child, ++ * ii_read_lock_child2, ii_write_lock_child2, ++ * ii_read_lock_child3, ii_write_lock_child3, ++ * ii_read_lock_parent, ii_write_lock_parent, ++ * ii_read_lock_parent2, ii_write_lock_parent2, ++ * ii_read_lock_parent3, ii_write_lock_parent3, ++ * ii_read_lock_new_child, ii_write_lock_new_child, ++ */ ++#define AuReadLockFunc(name, lsc) \ ++static inline void ii_read_lock_##name(struct inode *i) \ ++{ \ ++ au_rw_read_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); \ ++} ++ ++#define AuWriteLockFunc(name, lsc) \ ++static inline void ii_write_lock_##name(struct inode *i) \ ++{ \ ++ au_rw_write_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); \ ++} ++ ++#define AuRWLockFuncs(name, lsc) \ ++ AuReadLockFunc(name, lsc) \ ++ AuWriteLockFunc(name, lsc) ++ ++AuRWLockFuncs(child, CHILD); ++AuRWLockFuncs(child2, CHILD2); ++AuRWLockFuncs(child3, CHILD3); ++AuRWLockFuncs(parent, PARENT); ++AuRWLockFuncs(parent2, PARENT2); ++AuRWLockFuncs(parent3, PARENT3); ++AuRWLockFuncs(new_child, NEW_CHILD); ++ ++#undef AuReadLockFunc ++#undef AuWriteLockFunc ++#undef AuRWLockFuncs ++ ++#define ii_read_unlock(i) au_rw_read_unlock(&au_ii(i)->ii_rwsem) ++#define ii_write_unlock(i) au_rw_write_unlock(&au_ii(i)->ii_rwsem) ++#define ii_downgrade_lock(i) au_rw_dgrade_lock(&au_ii(i)->ii_rwsem) ++ ++#define IiMustNoWaiters(i) AuRwMustNoWaiters(&au_ii(i)->ii_rwsem) ++#define IiMustAnyLock(i) AuRwMustAnyLock(&au_ii(i)->ii_rwsem) ++#define IiMustWriteLock(i) AuRwMustWriteLock(&au_ii(i)->ii_rwsem) ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline void au_icntnr_init(struct au_icntnr *c) ++{ ++#ifdef CONFIG_AUFS_DEBUG ++ c->vfs_inode.i_mode = 0; ++#endif ++} ++ ++static inline unsigned int au_iigen(struct inode *inode, unsigned int *igflags) ++{ ++ unsigned int gen; ++ struct au_iinfo *iinfo; ++ struct au_iigen *iigen; ++ ++ iinfo = au_ii(inode); ++ iigen = &iinfo->ii_generation; ++ spin_lock(&iigen->ig_spin); ++ if (igflags) ++ *igflags = iigen->ig_flags; ++ gen = iigen->ig_generation; ++ spin_unlock(&iigen->ig_spin); ++ ++ return gen; ++} ++ ++/* tiny test for inode number */ ++/* tmpfs generation is too rough */ ++static inline int au_test_higen(struct inode *inode, struct inode *h_inode) ++{ ++ struct au_iinfo *iinfo; ++ ++ iinfo = au_ii(inode); ++ AuRwMustAnyLock(&iinfo->ii_rwsem); ++ return !(iinfo->ii_hsb1 == h_inode->i_sb ++ && iinfo->ii_higen == h_inode->i_generation); ++} ++ ++static inline void au_iigen_dec(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ struct au_iigen *iigen; ++ ++ iinfo = au_ii(inode); ++ iigen = &iinfo->ii_generation; ++ spin_lock(&iigen->ig_spin); ++ iigen->ig_generation--; ++ spin_unlock(&iigen->ig_spin); ++} ++ ++static inline int au_iigen_test(struct inode *inode, unsigned int sigen) ++{ ++ int err; ++ ++ err = 0; ++ if (unlikely(inode && au_iigen(inode, NULL) != sigen)) ++ err = -EIO; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_hinode *au_hinode(struct au_iinfo *iinfo, ++ aufs_bindex_t bindex) ++{ ++ return iinfo->ii_hinode + bindex; ++} ++ ++static inline int au_is_bad_inode(struct inode *inode) ++{ ++ return !!(is_bad_inode(inode) || !au_hinode(au_ii(inode), 0)); ++} ++ ++static inline aufs_bindex_t au_ii_br_id(struct inode *inode, ++ aufs_bindex_t bindex) ++{ ++ IiMustAnyLock(inode); ++ return au_hinode(au_ii(inode), bindex)->hi_id; ++} ++ ++static inline aufs_bindex_t au_ibtop(struct inode *inode) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_btop; ++} ++ ++static inline aufs_bindex_t au_ibbot(struct inode *inode) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_bbot; ++} ++ ++static inline struct au_vdir *au_ivdir(struct inode *inode) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_vdir; ++} ++ ++static inline struct dentry *au_hi_wh(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustAnyLock(inode); ++ return au_hinode(au_ii(inode), bindex)->hi_whdentry; ++} ++ ++static inline void au_set_ibtop(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustWriteLock(inode); ++ au_ii(inode)->ii_btop = bindex; ++} ++ ++static inline void au_set_ibbot(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustWriteLock(inode); ++ au_ii(inode)->ii_bbot = bindex; ++} ++ ++static inline void au_set_ivdir(struct inode *inode, struct au_vdir *vdir) ++{ ++ IiMustWriteLock(inode); ++ au_ii(inode)->ii_vdir = vdir; ++} ++ ++static inline struct au_hinode *au_hi(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustAnyLock(inode); ++ return au_hinode(au_ii(inode), bindex); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct dentry *au_pinned_parent(struct au_pin *pin) ++{ ++ if (pin) ++ return pin->parent; ++ return NULL; ++} ++ ++static inline struct inode *au_pinned_h_dir(struct au_pin *pin) ++{ ++ if (pin && pin->hdir) ++ return pin->hdir->hi_inode; ++ return NULL; ++} ++ ++static inline struct au_hinode *au_pinned_hdir(struct au_pin *pin) ++{ ++ if (pin) ++ return pin->hdir; ++ return NULL; ++} ++ ++static inline void au_pin_set_dentry(struct au_pin *pin, struct dentry *dentry) ++{ ++ if (pin) ++ pin->dentry = dentry; ++} ++ ++static inline void au_pin_set_parent_lflag(struct au_pin *pin, ++ unsigned char lflag) ++{ ++ if (pin) { ++ if (lflag) ++ au_fset_pin(pin->flags, DI_LOCKED); ++ else ++ au_fclr_pin(pin->flags, DI_LOCKED); ++ } ++} ++ ++#if 0 /* reserved */ ++static inline void au_pin_set_parent(struct au_pin *pin, struct dentry *parent) ++{ ++ if (pin) { ++ dput(pin->parent); ++ pin->parent = dget(parent); ++ } ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_branch; ++#ifdef CONFIG_AUFS_HNOTIFY ++struct au_hnotify_op { ++ void (*ctl)(struct au_hinode *hinode, int do_set); ++ int (*alloc)(struct au_hinode *hinode); ++ ++ /* ++ * if it returns true, the caller should free hinode->hi_notify, ++ * otherwise ->free() frees it. ++ */ ++ int (*free)(struct au_hinode *hinode, ++ struct au_hnotify *hn) __must_check; ++ ++ void (*fin)(void); ++ int (*init)(void); ++ ++ int (*reset_br)(unsigned int udba, struct au_branch *br, int perm); ++ void (*fin_br)(struct au_branch *br); ++ int (*init_br)(struct au_branch *br, int perm); ++}; ++ ++/* hnotify.c */ ++int au_hn_alloc(struct au_hinode *hinode, struct inode *inode); ++void au_hn_free(struct au_hinode *hinode); ++void au_hn_ctl(struct au_hinode *hinode, int do_set); ++void au_hn_reset(struct inode *inode, unsigned int flags); ++int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask, ++ const struct qstr *h_child_qstr, struct inode *h_child_inode); ++int au_hnotify_reset_br(unsigned int udba, struct au_branch *br, int perm); ++int au_hnotify_init_br(struct au_branch *br, int perm); ++void au_hnotify_fin_br(struct au_branch *br); ++int __init au_hnotify_init(void); ++void au_hnotify_fin(void); ++ ++/* hfsnotify.c */ ++extern const struct au_hnotify_op au_hnotify_op; ++ ++static inline ++void au_hn_init(struct au_hinode *hinode) ++{ ++ hinode->hi_notify = NULL; ++} ++ ++static inline struct au_hnotify *au_hn(struct au_hinode *hinode) ++{ ++ return hinode->hi_notify; ++} ++ ++#else ++AuStub(int, au_hn_alloc, return -EOPNOTSUPP, ++ struct au_hinode *hinode __maybe_unused, ++ struct inode *inode __maybe_unused) ++AuStub(struct au_hnotify *, au_hn, return NULL, struct au_hinode *hinode) ++AuStubVoid(au_hn_free, struct au_hinode *hinode __maybe_unused) ++AuStubVoid(au_hn_ctl, struct au_hinode *hinode __maybe_unused, ++ int do_set __maybe_unused) ++AuStubVoid(au_hn_reset, struct inode *inode __maybe_unused, ++ unsigned int flags __maybe_unused) ++AuStubInt0(au_hnotify_reset_br, unsigned int udba __maybe_unused, ++ struct au_branch *br __maybe_unused, ++ int perm __maybe_unused) ++AuStubInt0(au_hnotify_init_br, struct au_branch *br __maybe_unused, ++ int perm __maybe_unused) ++AuStubVoid(au_hnotify_fin_br, struct au_branch *br __maybe_unused) ++AuStubInt0(__init au_hnotify_init, void) ++AuStubVoid(au_hnotify_fin, void) ++AuStubVoid(au_hn_init, struct au_hinode *hinode __maybe_unused) ++#endif /* CONFIG_AUFS_HNOTIFY */ ++ ++static inline void au_hn_suspend(struct au_hinode *hdir) ++{ ++ au_hn_ctl(hdir, /*do_set*/0); ++} ++ ++static inline void au_hn_resume(struct au_hinode *hdir) ++{ ++ au_hn_ctl(hdir, /*do_set*/1); ++} ++ ++static inline void au_hn_inode_lock(struct au_hinode *hdir) ++{ ++ inode_lock(hdir->hi_inode); ++ au_hn_suspend(hdir); ++} ++ ++static inline void au_hn_inode_lock_nested(struct au_hinode *hdir, ++ unsigned int sc __maybe_unused) ++{ ++ inode_lock_nested(hdir->hi_inode, sc); ++ au_hn_suspend(hdir); ++} ++ ++#if 0 /* unused */ ++#include "vfsub.h" ++static inline void au_hn_inode_lock_shared_nested(struct au_hinode *hdir, ++ unsigned int sc) ++{ ++ inode_lock_shared_nested(hdir->hi_inode, sc); ++ au_hn_suspend(hdir); ++} ++#endif ++ ++static inline void au_hn_inode_unlock(struct au_hinode *hdir) ++{ ++ au_hn_resume(hdir); ++ inode_unlock(hdir->hi_inode); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_INODE_H__ */ +diff -Nurp linux-5.15.37/fs/aufs/ioctl.c linux-5.15.37-aufs/fs/aufs/ioctl.c +--- linux-5.15.37/fs/aufs/ioctl.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/ioctl.c 2022-04-08 20:22:30.614616573 +0300 +@@ -0,0 +1,207 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * ioctl ++ * plink-management and readdir in userspace. ++ * assist the pathconf(3) wrapper library. ++ * move-down ++ * File-based Hierarchical Storage Management. ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++static int au_wbr_fd(struct path *path, struct aufs_wbr_fd __user *arg) ++{ ++ int err, fd; ++ aufs_bindex_t wbi, bindex, bbot; ++ struct file *h_file; ++ struct super_block *sb; ++ struct dentry *root; ++ struct au_branch *br; ++ struct aufs_wbr_fd wbrfd = { ++ .oflags = au_dir_roflags, ++ .brid = -1 ++ }; ++ const int valid = O_RDONLY | O_NONBLOCK | O_LARGEFILE | O_DIRECTORY ++ | O_NOATIME | O_CLOEXEC; ++ ++ AuDebugOn(wbrfd.oflags & ~valid); ++ ++ if (arg) { ++ err = copy_from_user(&wbrfd, arg, sizeof(wbrfd)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ goto out; ++ } ++ ++ err = -EINVAL; ++ AuDbg("wbrfd{0%o, %d}\n", wbrfd.oflags, wbrfd.brid); ++ wbrfd.oflags |= au_dir_roflags; ++ AuDbg("0%o\n", wbrfd.oflags); ++ if (unlikely(wbrfd.oflags & ~valid)) ++ goto out; ++ } ++ ++ fd = get_unused_fd_flags(0); ++ err = fd; ++ if (unlikely(fd < 0)) ++ goto out; ++ ++ h_file = ERR_PTR(-EINVAL); ++ wbi = 0; ++ br = NULL; ++ sb = path->dentry->d_sb; ++ root = sb->s_root; ++ aufs_read_lock(root, AuLock_IR); ++ bbot = au_sbbot(sb); ++ if (wbrfd.brid >= 0) { ++ wbi = au_br_index(sb, wbrfd.brid); ++ if (unlikely(wbi < 0 || wbi > bbot)) ++ goto out_unlock; ++ } ++ ++ h_file = ERR_PTR(-ENOENT); ++ br = au_sbr(sb, wbi); ++ if (!au_br_writable(br->br_perm)) { ++ if (arg) ++ goto out_unlock; ++ ++ bindex = wbi + 1; ++ wbi = -1; ++ for (; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_writable(br->br_perm)) { ++ wbi = bindex; ++ br = au_sbr(sb, wbi); ++ break; ++ } ++ } ++ } ++ AuDbg("wbi %d\n", wbi); ++ if (wbi >= 0) ++ h_file = au_h_open(root, wbi, wbrfd.oflags, NULL, ++ /*force_wr*/0); ++ ++out_unlock: ++ aufs_read_unlock(root, AuLock_IR); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out_fd; ++ ++ au_lcnt_dec(&br->br_nfiles); /* cf. au_h_open() */ ++ fd_install(fd, h_file); ++ err = fd; ++ goto out; /* success */ ++ ++out_fd: ++ put_unused_fd(fd); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ long err; ++ struct dentry *dentry; ++ ++ switch (cmd) { ++ case AUFS_CTL_RDU: ++ case AUFS_CTL_RDU_INO: ++ err = au_rdu_ioctl(file, cmd, arg); ++ break; ++ ++ case AUFS_CTL_WBR_FD: ++ err = au_wbr_fd(&file->f_path, (void __user *)arg); ++ break; ++ ++ case AUFS_CTL_IBUSY: ++ err = au_ibusy_ioctl(file, arg); ++ break; ++ ++ case AUFS_CTL_BRINFO: ++ err = au_brinfo_ioctl(file, arg); ++ break; ++ ++ case AUFS_CTL_FHSM_FD: ++ dentry = file->f_path.dentry; ++ if (IS_ROOT(dentry)) ++ err = au_fhsm_fd(dentry->d_sb, arg); ++ else ++ err = -ENOTTY; ++ break; ++ ++ default: ++ /* do not call the lower */ ++ AuDbg("0x%x\n", cmd); ++ err = -ENOTTY; ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ long err; ++ ++ switch (cmd) { ++ case AUFS_CTL_MVDOWN: ++ err = au_mvdown(file->f_path.dentry, (void __user *)arg); ++ break; ++ ++ case AUFS_CTL_WBR_FD: ++ err = au_wbr_fd(&file->f_path, (void __user *)arg); ++ break; ++ ++ default: ++ /* do not call the lower */ ++ AuDbg("0x%x\n", cmd); ++ err = -ENOTTY; ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++#ifdef CONFIG_COMPAT ++long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ long err; ++ ++ switch (cmd) { ++ case AUFS_CTL_RDU: ++ case AUFS_CTL_RDU_INO: ++ err = au_rdu_compat_ioctl(file, cmd, arg); ++ break; ++ ++ case AUFS_CTL_IBUSY: ++ err = au_ibusy_compat_ioctl(file, arg); ++ break; ++ ++ case AUFS_CTL_BRINFO: ++ err = au_brinfo_compat_ioctl(file, arg); ++ break; ++ ++ default: ++ err = aufs_ioctl_dir(file, cmd, arg); ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++long aufs_compat_ioctl_nondir(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ return aufs_ioctl_nondir(file, cmd, (unsigned long)compat_ptr(arg)); ++} ++#endif +diff -Nurp linux-5.15.37/fs/aufs/i_op_add.c linux-5.15.37-aufs/fs/aufs/i_op_add.c +--- linux-5.15.37/fs/aufs/i_op_add.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/i_op_add.c 2022-04-08 20:22:30.613616524 +0300 +@@ -0,0 +1,928 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode operations (add entry) ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* ++ * final procedure of adding a new entry, except link(2). ++ * remove whiteout, instantiate, copyup the parent dir's times and size ++ * and update version. ++ * if it failed, re-create the removed whiteout. ++ */ ++static int epilog(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct dentry *dentry) ++{ ++ int err, rerr; ++ aufs_bindex_t bwh; ++ struct path h_path; ++ struct super_block *sb; ++ struct inode *inode, *h_dir; ++ struct dentry *wh; ++ ++ bwh = -1; ++ sb = dir->i_sb; ++ if (wh_dentry) { ++ h_dir = d_inode(wh_dentry->d_parent); /* dir inode is locked */ ++ IMustLock(h_dir); ++ AuDebugOn(au_h_iptr(dir, bindex) != h_dir); ++ bwh = au_dbwh(dentry); ++ h_path.dentry = wh_dentry; ++ h_path.mnt = au_sbr_mnt(sb, bindex); ++ err = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path, ++ dentry); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ inode = au_new_inode(dentry, /*must_new*/1); ++ if (!IS_ERR(inode)) { ++ d_instantiate(dentry, inode); ++ dir = d_inode(dentry->d_parent); /* dir inode is locked */ ++ IMustLock(dir); ++ au_dir_ts(dir, bindex); ++ inode_inc_iversion(dir); ++ au_fhsm_wrote(sb, bindex, /*force*/0); ++ return 0; /* success */ ++ } ++ ++ err = PTR_ERR(inode); ++ if (!wh_dentry) ++ goto out; ++ ++ /* revert */ ++ /* dir inode is locked */ ++ wh = au_wh_create(dentry, bwh, wh_dentry->d_parent); ++ rerr = PTR_ERR(wh); ++ if (IS_ERR(wh)) { ++ AuIOErr("%pd reverting whiteout failed(%d, %d)\n", ++ dentry, err, rerr); ++ err = -EIO; ++ } else ++ dput(wh); ++ ++out: ++ return err; ++} ++ ++static int au_d_may_add(struct dentry *dentry) ++{ ++ int err; ++ ++ err = 0; ++ if (unlikely(d_unhashed(dentry))) ++ err = -ENOENT; ++ if (unlikely(d_really_is_positive(dentry))) ++ err = -EEXIST; ++ return err; ++} ++ ++/* ++ * simple tests for the adding inode operations. ++ * following the checks in vfs, plus the parent-child relationship. ++ */ ++int au_may_add(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, int isdir) ++{ ++ int err; ++ umode_t h_mode; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ ++ err = -ENAMETOOLONG; ++ if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) ++ goto out; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (d_really_is_negative(dentry)) { ++ err = -EEXIST; ++ if (unlikely(d_is_positive(h_dentry))) ++ goto out; ++ } else { ++ /* rename(2) case */ ++ err = -EIO; ++ if (unlikely(d_is_negative(h_dentry))) ++ goto out; ++ h_inode = d_inode(h_dentry); ++ if (unlikely(!h_inode->i_nlink)) ++ goto out; ++ ++ h_mode = h_inode->i_mode; ++ if (!isdir) { ++ err = -EISDIR; ++ if (unlikely(S_ISDIR(h_mode))) ++ goto out; ++ } else if (unlikely(!S_ISDIR(h_mode))) { ++ err = -ENOTDIR; ++ goto out; ++ } ++ } ++ ++ err = 0; ++ /* expected parent dir is locked */ ++ if (unlikely(h_parent != h_dentry->d_parent)) ++ err = -EIO; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * initial procedure of adding a new entry. ++ * prepare writable branch and the parent dir, lock it, ++ * and lookup whiteout for the new entry. ++ */ ++static struct dentry* ++lock_hdir_lkup_wh(struct dentry *dentry, struct au_dtime *dt, ++ struct dentry *src_dentry, struct au_pin *pin, ++ struct au_wr_dir_args *wr_dir_args) ++{ ++ struct dentry *wh_dentry, *h_parent; ++ struct super_block *sb; ++ struct au_branch *br; ++ int err; ++ unsigned int udba; ++ aufs_bindex_t bcpup; ++ ++ AuDbg("%pd\n", dentry); ++ ++ err = au_wr_dir(dentry, src_dentry, wr_dir_args); ++ bcpup = err; ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err < 0)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ udba = au_opt_udba(sb); ++ err = au_pin(pin, dentry, bcpup, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ h_parent = au_pinned_h_parent(pin); ++ if (udba != AuOpt_UDBA_NONE ++ && au_dbtop(dentry) == bcpup) ++ err = au_may_add(dentry, bcpup, h_parent, ++ au_ftest_wrdir(wr_dir_args->flags, ISDIR)); ++ else if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) ++ err = -ENAMETOOLONG; ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_unpin; ++ ++ br = au_sbr(sb, bcpup); ++ if (dt) { ++ struct path tmp = { ++ .dentry = h_parent, ++ .mnt = au_br_mnt(br) ++ }; ++ au_dtime_store(dt, au_pinned_parent(pin), &tmp); ++ } ++ ++ wh_dentry = NULL; ++ if (bcpup != au_dbwh(dentry)) ++ goto out; /* success */ ++ ++ /* ++ * ENAMETOOLONG here means that if we allowed create such name, then it ++ * would not be able to removed in the future. So we don't allow such ++ * name here and we don't handle ENAMETOOLONG differently here. ++ */ ++ wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, br); ++ ++out_unpin: ++ if (IS_ERR(wh_dentry)) ++ au_unpin(pin); ++out: ++ return wh_dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++enum { Mknod, Symlink, Creat }; ++struct simple_arg { ++ int type; ++ union { ++ struct { ++ umode_t mode; ++ bool want_excl; ++ bool try_aopen; ++ struct vfsub_aopen_args *aopen; ++ } c; ++ struct { ++ const char *symname; ++ } s; ++ struct { ++ umode_t mode; ++ dev_t dev; ++ } m; ++ } u; ++}; ++ ++static int add_simple(struct inode *dir, struct dentry *dentry, ++ struct simple_arg *arg) ++{ ++ int err, rerr; ++ aufs_bindex_t btop; ++ unsigned char created; ++ const unsigned char try_aopen ++ = (arg->type == Creat && arg->u.c.try_aopen); ++ struct vfsub_aopen_args *aopen = arg->u.c.aopen; ++ struct dentry *wh_dentry, *parent; ++ struct inode *h_dir; ++ struct super_block *sb; ++ struct au_branch *br; ++ /* to reduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct au_pin pin; ++ struct path h_path; ++ struct au_wr_dir_args wr_dir_args; ++ } *a; ++ ++ AuDbg("%pd\n", dentry); ++ IMustLock(dir); ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ a->wr_dir_args.force_btgt = -1; ++ a->wr_dir_args.flags = AuWrDir_ADD_ENTRY; ++ ++ parent = dentry->d_parent; /* dir inode is locked */ ++ if (!try_aopen) { ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_free; ++ } ++ err = au_d_may_add(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ if (!try_aopen) ++ di_write_lock_parent(parent); ++ wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL, ++ &a->pin, &a->wr_dir_args); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ btop = au_dbtop(dentry); ++ sb = dentry->d_sb; ++ br = au_sbr(sb, btop); ++ a->h_path.dentry = au_h_dptr(dentry, btop); ++ a->h_path.mnt = au_br_mnt(br); ++ h_dir = au_pinned_h_dir(&a->pin); ++ switch (arg->type) { ++ case Creat: ++ if (!try_aopen || !h_dir->i_op->atomic_open) { ++ err = vfsub_create(h_dir, &a->h_path, arg->u.c.mode, ++ arg->u.c.want_excl); ++ created = !err; ++ if (!err && try_aopen) ++ aopen->file->f_mode |= FMODE_CREATED; ++ } else { ++ aopen->br = br; ++ err = vfsub_atomic_open(h_dir, a->h_path.dentry, aopen); ++ AuDbg("err %d\n", err); ++ AuDbgFile(aopen->file); ++ created = err >= 0 ++ && !!(aopen->file->f_mode & FMODE_CREATED); ++ } ++ break; ++ case Symlink: ++ err = vfsub_symlink(h_dir, &a->h_path, arg->u.s.symname); ++ created = !err; ++ break; ++ case Mknod: ++ err = vfsub_mknod(h_dir, &a->h_path, arg->u.m.mode, ++ arg->u.m.dev); ++ created = !err; ++ break; ++ default: ++ BUG(); ++ } ++ if (unlikely(err < 0)) ++ goto out_unpin; ++ ++ err = epilog(dir, btop, wh_dentry, dentry); ++ if (!err) ++ goto out_unpin; /* success */ ++ ++ /* revert */ ++ if (created /* && d_is_positive(a->h_path.dentry) */) { ++ /* no delegation since it is just created */ ++ rerr = vfsub_unlink(h_dir, &a->h_path, /*delegated*/NULL, ++ /*force*/0); ++ if (rerr) { ++ AuIOErr("%pd revert failure(%d, %d)\n", ++ dentry, err, rerr); ++ err = -EIO; ++ } ++ au_dtime_revert(&a->dt); ++ } ++ if (try_aopen && h_dir->i_op->atomic_open ++ && (aopen->file->f_mode & FMODE_OPENED)) ++ /* aopen->file is still opened */ ++ au_lcnt_dec(&aopen->br->br_nfiles); ++ ++out_unpin: ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++out_parent: ++ if (!try_aopen) ++ di_write_unlock(parent); ++out_unlock: ++ if (unlikely(err)) { ++ au_update_dbtop(dentry); ++ d_drop(dentry); ++ } ++ if (!try_aopen) ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ au_kfree_rcu(a); ++out: ++ return err; ++} ++ ++int aufs_mknod(struct user_namespace *userns, struct inode *dir, ++ struct dentry *dentry, umode_t mode, dev_t dev) ++{ ++ struct simple_arg arg = { ++ .type = Mknod, ++ .u.m = { ++ .mode = mode, ++ .dev = dev ++ } ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int aufs_symlink(struct user_namespace *userns, struct inode *dir, ++ struct dentry *dentry, const char *symname) ++{ ++ struct simple_arg arg = { ++ .type = Symlink, ++ .u.s.symname = symname ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int aufs_create(struct user_namespace *userns, struct inode *dir, ++ struct dentry *dentry, umode_t mode, bool want_excl) ++{ ++ struct simple_arg arg = { ++ .type = Creat, ++ .u.c = { ++ .mode = mode, ++ .want_excl = want_excl ++ } ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int au_aopen_or_create(struct inode *dir, struct dentry *dentry, ++ struct vfsub_aopen_args *aopen_args) ++{ ++ struct simple_arg arg = { ++ .type = Creat, ++ .u.c = { ++ .mode = aopen_args->create_mode, ++ .want_excl = aopen_args->open_flag & O_EXCL, ++ .try_aopen = true, ++ .aopen = aopen_args ++ } ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int aufs_tmpfile(struct user_namespace *userns, struct inode *dir, ++ struct dentry *dentry, umode_t mode) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct super_block *sb; ++ struct dentry *parent, *h_parent, *h_dentry; ++ struct inode *h_dir, *inode; ++ struct vfsmount *h_mnt; ++ struct user_namespace *h_userns; ++ struct au_wr_dir_args wr_dir_args = { ++ .force_btgt = -1, ++ .flags = AuWrDir_TMPFILE ++ }; ++ ++ /* copy-up may happen */ ++ inode_lock(dir); ++ ++ sb = dir->i_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_di_init(dentry); ++ if (unlikely(err)) ++ goto out_si; ++ ++ err = -EBUSY; ++ parent = d_find_any_alias(dir); ++ AuDebugOn(!parent); ++ di_write_lock_parent(parent); ++ if (unlikely(d_inode(parent) != dir)) ++ goto out_parent; ++ ++ err = au_digen_test(parent, au_sigen(sb)); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ bindex = au_dbtop(parent); ++ au_set_dbtop(dentry, bindex); ++ au_set_dbbot(dentry, bindex); ++ err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args); ++ bindex = err; ++ if (unlikely(err < 0)) ++ goto out_parent; ++ ++ err = -EOPNOTSUPP; ++ h_dir = au_h_iptr(dir, bindex); ++ if (unlikely(!h_dir->i_op->tmpfile)) ++ goto out_parent; ++ ++ h_mnt = au_sbr_mnt(sb, bindex); ++ err = vfsub_mnt_want_write(h_mnt); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ h_userns = mnt_user_ns(h_mnt); ++ h_parent = au_h_dptr(parent, bindex); ++ h_dentry = vfs_tmpfile(h_userns, h_parent, mode, /*open_flag*/0); ++ if (IS_ERR(h_dentry)) { ++ err = PTR_ERR(h_dentry); ++ goto out_mnt; ++ } ++ ++ au_set_dbtop(dentry, bindex); ++ au_set_dbbot(dentry, bindex); ++ au_set_h_dptr(dentry, bindex, dget(h_dentry)); ++ inode = au_new_inode(dentry, /*must_new*/1); ++ if (IS_ERR(inode)) { ++ err = PTR_ERR(inode); ++ au_set_h_dptr(dentry, bindex, NULL); ++ au_set_dbtop(dentry, -1); ++ au_set_dbbot(dentry, -1); ++ } else { ++ if (!inode->i_nlink) ++ set_nlink(inode, 1); ++ d_tmpfile(dentry, inode); ++ au_di(dentry)->di_tmpfile = 1; ++ ++ /* update without i_mutex */ ++ if (au_ibtop(dir) == au_dbtop(dentry)) ++ au_cpup_attr_timesizes(dir); ++ } ++ dput(h_dentry); ++ ++out_mnt: ++ vfsub_mnt_drop_write(h_mnt); ++out_parent: ++ di_write_unlock(parent); ++ dput(parent); ++ di_write_unlock(dentry); ++ if (unlikely(err)) { ++ au_di_fin(dentry); ++ dentry->d_fsdata = NULL; ++ } ++out_si: ++ si_read_unlock(sb); ++out: ++ inode_unlock(dir); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_link_args { ++ aufs_bindex_t bdst, bsrc; ++ struct au_pin pin; ++ struct path h_path; ++ struct dentry *src_parent, *parent; ++}; ++ ++static int au_cpup_before_link(struct dentry *src_dentry, ++ struct au_link_args *a) ++{ ++ int err; ++ struct dentry *h_src_dentry; ++ struct au_cp_generic cpg = { ++ .dentry = src_dentry, ++ .bdst = a->bdst, ++ .bsrc = a->bsrc, ++ .len = -1, ++ .pin = &a->pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN /* | AuCpup_KEEPLINO */ ++ }; ++ ++ di_read_lock_parent(a->src_parent, AuLock_IR); ++ err = au_test_and_cpup_dirs(src_dentry, a->bdst); ++ if (unlikely(err)) ++ goto out; ++ ++ h_src_dentry = au_h_dptr(src_dentry, a->bsrc); ++ err = au_pin(&a->pin, src_dentry, a->bdst, ++ au_opt_udba(src_dentry->d_sb), ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&a->pin); ++ ++out: ++ di_read_unlock(a->src_parent, AuLock_IR); ++ return err; ++} ++ ++static int au_cpup_or_link(struct dentry *src_dentry, struct dentry *dentry, ++ struct au_link_args *a) ++{ ++ int err; ++ unsigned char plink; ++ aufs_bindex_t bbot; ++ struct dentry *h_src_dentry; ++ struct inode *h_inode, *inode, *delegated; ++ struct super_block *sb; ++ struct file *h_file; ++ ++ plink = 0; ++ h_inode = NULL; ++ sb = src_dentry->d_sb; ++ inode = d_inode(src_dentry); ++ if (au_ibtop(inode) <= a->bdst) ++ h_inode = au_h_iptr(inode, a->bdst); ++ if (!h_inode || !h_inode->i_nlink) { ++ /* copyup src_dentry as the name of dentry. */ ++ bbot = au_dbbot(dentry); ++ if (bbot < a->bsrc) ++ au_set_dbbot(dentry, a->bsrc); ++ au_set_h_dptr(dentry, a->bsrc, ++ dget(au_h_dptr(src_dentry, a->bsrc))); ++ dget(a->h_path.dentry); ++ au_set_h_dptr(dentry, a->bdst, NULL); ++ AuDbg("temporary d_inode...\n"); ++ spin_lock(&dentry->d_lock); ++ dentry->d_inode = d_inode(src_dentry); /* tmp */ ++ spin_unlock(&dentry->d_lock); ++ h_file = au_h_open_pre(dentry, a->bsrc, /*force_wr*/0); ++ if (IS_ERR(h_file)) ++ err = PTR_ERR(h_file); ++ else { ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = a->bdst, ++ .bsrc = -1, ++ .len = -1, ++ .pin = &a->pin, ++ .flags = AuCpup_KEEPLINO ++ }; ++ err = au_sio_cpup_simple(&cpg); ++ au_h_open_post(dentry, a->bsrc, h_file); ++ if (!err) { ++ dput(a->h_path.dentry); ++ a->h_path.dentry = au_h_dptr(dentry, a->bdst); ++ } else ++ au_set_h_dptr(dentry, a->bdst, ++ a->h_path.dentry); ++ } ++ spin_lock(&dentry->d_lock); ++ dentry->d_inode = NULL; /* restore */ ++ spin_unlock(&dentry->d_lock); ++ AuDbg("temporary d_inode...done\n"); ++ au_set_h_dptr(dentry, a->bsrc, NULL); ++ au_set_dbbot(dentry, bbot); ++ } else { ++ /* the inode of src_dentry already exists on a.bdst branch */ ++ h_src_dentry = d_find_alias(h_inode); ++ if (!h_src_dentry && au_plink_test(inode)) { ++ plink = 1; ++ h_src_dentry = au_plink_lkup(inode, a->bdst); ++ err = PTR_ERR(h_src_dentry); ++ if (IS_ERR(h_src_dentry)) ++ goto out; ++ ++ if (unlikely(d_is_negative(h_src_dentry))) { ++ dput(h_src_dentry); ++ h_src_dentry = NULL; ++ } ++ ++ } ++ if (h_src_dentry) { ++ delegated = NULL; ++ err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin), ++ &a->h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ dput(h_src_dentry); ++ } else { ++ AuIOErr("no dentry found for hi%lu on b%d\n", ++ h_inode->i_ino, a->bdst); ++ err = -EIO; ++ } ++ } ++ ++ if (!err && !plink) ++ au_plink_append(inode, a->bdst, a->h_path.dentry); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int aufs_link(struct dentry *src_dentry, struct inode *dir, ++ struct dentry *dentry) ++{ ++ int err, rerr; ++ struct au_dtime dt; ++ struct au_link_args *a; ++ struct dentry *wh_dentry, *h_src_dentry; ++ struct inode *inode, *delegated; ++ struct super_block *sb; ++ struct au_wr_dir_args wr_dir_args = { ++ /* .force_btgt = -1, */ ++ .flags = AuWrDir_ADD_ENTRY ++ }; ++ ++ IMustLock(dir); ++ inode = d_inode(src_dentry); ++ IMustLock(inode); ++ ++ err = -ENOMEM; ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ a->parent = dentry->d_parent; /* dir inode is locked */ ++ err = aufs_read_and_write_lock2(dentry, src_dentry, ++ AuLock_NOPLM | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_kfree; ++ err = au_d_linkable(src_dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ err = au_d_may_add(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ a->src_parent = dget_parent(src_dentry); ++ wr_dir_args.force_btgt = au_ibtop(inode); ++ ++ di_write_lock_parent(a->parent); ++ wr_dir_args.force_btgt = au_wbr(dentry, wr_dir_args.force_btgt); ++ wh_dentry = lock_hdir_lkup_wh(dentry, &dt, src_dentry, &a->pin, ++ &wr_dir_args); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ a->bdst = au_dbtop(dentry); ++ a->h_path.dentry = au_h_dptr(dentry, a->bdst); ++ a->h_path.mnt = au_sbr_mnt(sb, a->bdst); ++ a->bsrc = au_ibtop(inode); ++ h_src_dentry = au_h_d_alias(src_dentry, a->bsrc); ++ if (!h_src_dentry && au_di(src_dentry)->di_tmpfile) ++ h_src_dentry = dget(au_hi_wh(inode, a->bsrc)); ++ if (!h_src_dentry) { ++ a->bsrc = au_dbtop(src_dentry); ++ h_src_dentry = au_h_d_alias(src_dentry, a->bsrc); ++ AuDebugOn(!h_src_dentry); ++ } else if (IS_ERR(h_src_dentry)) { ++ err = PTR_ERR(h_src_dentry); ++ goto out_parent; ++ } ++ ++ /* ++ * aufs doesn't touch the credential so ++ * security_dentry_create_files_as() is unnecessary. ++ */ ++ if (au_opt_test(au_mntflags(sb), PLINK)) { ++ if (a->bdst < a->bsrc ++ /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */) ++ err = au_cpup_or_link(src_dentry, dentry, a); ++ else { ++ delegated = NULL; ++ err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin), ++ &a->h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ } ++ dput(h_src_dentry); ++ } else { ++ /* ++ * copyup src_dentry to the branch we process, ++ * and then link(2) to it. ++ */ ++ dput(h_src_dentry); ++ if (a->bdst < a->bsrc ++ /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */) { ++ au_unpin(&a->pin); ++ di_write_unlock(a->parent); ++ err = au_cpup_before_link(src_dentry, a); ++ di_write_lock_parent(a->parent); ++ if (!err) ++ err = au_pin(&a->pin, dentry, a->bdst, ++ au_opt_udba(sb), ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_wh; ++ } ++ if (!err) { ++ h_src_dentry = au_h_dptr(src_dentry, a->bdst); ++ err = -ENOENT; ++ if (h_src_dentry && d_is_positive(h_src_dentry)) { ++ delegated = NULL; ++ err = vfsub_link(h_src_dentry, ++ au_pinned_h_dir(&a->pin), ++ &a->h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry" ++ " for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ } ++ } ++ } ++ if (unlikely(err)) ++ goto out_unpin; ++ ++ if (wh_dentry) { ++ a->h_path.dentry = wh_dentry; ++ err = au_wh_unlink_dentry(au_pinned_h_dir(&a->pin), &a->h_path, ++ dentry); ++ if (unlikely(err)) ++ goto out_revert; ++ } ++ ++ au_dir_ts(dir, a->bdst); ++ inode_inc_iversion(dir); ++ inc_nlink(inode); ++ inode->i_ctime = dir->i_ctime; ++ d_instantiate(dentry, au_igrab(inode)); ++ if (d_unhashed(a->h_path.dentry)) ++ /* some filesystem calls d_drop() */ ++ d_drop(dentry); ++ /* some filesystems consume an inode even hardlink */ ++ au_fhsm_wrote(sb, a->bdst, /*force*/0); ++ goto out_unpin; /* success */ ++ ++out_revert: ++ /* no delegation since it is just created */ ++ rerr = vfsub_unlink(au_pinned_h_dir(&a->pin), &a->h_path, ++ /*delegated*/NULL, /*force*/0); ++ if (unlikely(rerr)) { ++ AuIOErr("%pd reverting failed(%d, %d)\n", dentry, err, rerr); ++ err = -EIO; ++ } ++ au_dtime_revert(&dt); ++out_unpin: ++ au_unpin(&a->pin); ++out_wh: ++ dput(wh_dentry); ++out_parent: ++ di_write_unlock(a->parent); ++ dput(a->src_parent); ++out_unlock: ++ if (unlikely(err)) { ++ au_update_dbtop(dentry); ++ d_drop(dentry); ++ } ++ aufs_read_and_write_unlock2(dentry, src_dentry); ++out_kfree: ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int aufs_mkdir(struct user_namespace *userns, struct inode *dir, ++ struct dentry *dentry, umode_t mode) ++{ ++ int err, rerr; ++ aufs_bindex_t bindex; ++ unsigned char diropq; ++ struct path h_path; ++ struct dentry *wh_dentry, *parent, *opq_dentry; ++ struct inode *h_inode; ++ struct super_block *sb; ++ struct { ++ struct au_pin pin; ++ struct au_dtime dt; ++ } *a; /* reduce the stack usage */ ++ struct au_wr_dir_args wr_dir_args = { ++ .force_btgt = -1, ++ .flags = AuWrDir_ADD_ENTRY | AuWrDir_ISDIR ++ }; ++ ++ IMustLock(dir); ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_free; ++ err = au_d_may_add(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ parent = dentry->d_parent; /* dir inode is locked */ ++ di_write_lock_parent(parent); ++ wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL, ++ &a->pin, &wr_dir_args); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ sb = dentry->d_sb; ++ bindex = au_dbtop(dentry); ++ h_path.dentry = au_h_dptr(dentry, bindex); ++ h_path.mnt = au_sbr_mnt(sb, bindex); ++ err = vfsub_mkdir(au_pinned_h_dir(&a->pin), &h_path, mode); ++ if (unlikely(err)) ++ goto out_unpin; ++ ++ /* make the dir opaque */ ++ diropq = 0; ++ h_inode = d_inode(h_path.dentry); ++ if (wh_dentry ++ || au_opt_test(au_mntflags(sb), ALWAYS_DIROPQ)) { ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ opq_dentry = au_diropq_create(dentry, bindex); ++ inode_unlock(h_inode); ++ err = PTR_ERR(opq_dentry); ++ if (IS_ERR(opq_dentry)) ++ goto out_dir; ++ dput(opq_dentry); ++ diropq = 1; ++ } ++ ++ err = epilog(dir, bindex, wh_dentry, dentry); ++ if (!err) { ++ inc_nlink(dir); ++ goto out_unpin; /* success */ ++ } ++ ++ /* revert */ ++ if (diropq) { ++ AuLabel(revert opq); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ rerr = au_diropq_remove(dentry, bindex); ++ inode_unlock(h_inode); ++ if (rerr) { ++ AuIOErr("%pd reverting diropq failed(%d, %d)\n", ++ dentry, err, rerr); ++ err = -EIO; ++ } ++ } ++ ++out_dir: ++ AuLabel(revert dir); ++ rerr = vfsub_rmdir(au_pinned_h_dir(&a->pin), &h_path); ++ if (rerr) { ++ AuIOErr("%pd reverting dir failed(%d, %d)\n", ++ dentry, err, rerr); ++ err = -EIO; ++ } ++ au_dtime_revert(&a->dt); ++out_unpin: ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++out_parent: ++ di_write_unlock(parent); ++out_unlock: ++ if (unlikely(err)) { ++ au_update_dbtop(dentry); ++ d_drop(dentry); ++ } ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ au_kfree_rcu(a); ++out: ++ return err; ++} +diff -Nurp linux-5.15.37/fs/aufs/i_op.c linux-5.15.37-aufs/fs/aufs/i_op.c +--- linux-5.15.37/fs/aufs/i_op.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/i_op.c 2022-04-08 20:22:30.613616524 +0300 +@@ -0,0 +1,1499 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode operations (except add/del/rename) ++ */ ++ ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++static int h_permission(struct inode *h_inode, int mask, ++ struct path *h_path, int brperm) ++{ ++ int err; ++ const unsigned char write_mask = !!(mask & (MAY_WRITE | MAY_APPEND)); ++ struct user_namespace *h_userns; ++ ++ err = -EPERM; ++ if (write_mask && IS_IMMUTABLE(h_inode)) ++ goto out; ++ ++ err = -EACCES; ++ if (((mask & MAY_EXEC) ++ && S_ISREG(h_inode->i_mode) ++ && (path_noexec(h_path) ++ || !(h_inode->i_mode & 0111)))) ++ goto out; ++ ++ /* ++ * - skip the lower fs test in the case of write to ro branch. ++ * - nfs dir permission write check is optimized, but a policy for ++ * link/rename requires a real check. ++ * - nfs always sets SB_POSIXACL regardless its mount option 'noacl.' ++ * in this case, generic_permission() returns -EOPNOTSUPP. ++ */ ++ h_userns = mnt_user_ns(h_path->mnt); ++ if ((write_mask && !au_br_writable(brperm)) ++ || (au_test_nfs(h_inode->i_sb) && S_ISDIR(h_inode->i_mode) ++ && write_mask && !(mask & MAY_READ)) ++ || !h_inode->i_op->permission) { ++ /* AuLabel(generic_permission); */ ++ /* AuDbg("get_acl %ps\n", h_inode->i_op->get_acl); */ ++ err = generic_permission(h_userns, h_inode, mask); ++ if (err == -EOPNOTSUPP && au_test_nfs_noacl(h_inode)) ++ err = h_inode->i_op->permission(h_userns, h_inode, ++ mask); ++ AuTraceErr(err); ++ } else { ++ /* AuLabel(h_inode->permission); */ ++ err = h_inode->i_op->permission(h_userns, h_inode, mask); ++ AuTraceErr(err); ++ } ++ ++ if (!err) ++ err = devcgroup_inode_permission(h_inode, mask); ++ if (!err) ++ err = security_inode_permission(h_inode, mask); ++ ++out: ++ return err; ++} ++ ++static int aufs_permission(struct user_namespace *userns, struct inode *inode, ++ int mask) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ const unsigned char isdir = !!S_ISDIR(inode->i_mode), ++ write_mask = !!(mask & (MAY_WRITE | MAY_APPEND)); ++ struct inode *h_inode; ++ struct super_block *sb; ++ struct au_branch *br; ++ ++ /* todo: support rcu-walk? */ ++ if (mask & MAY_NOT_BLOCK) ++ return -ECHILD; ++ ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ ii_read_lock_child(inode); ++#if 0 /* reserved for future use */ ++ /* ++ * This test may be rather 'too much' since the test is essentially done ++ * in the aufs_lookup(). Theoretically it is possible that the inode ++ * generation doesn't match to the superblock's here. But it isn't a ++ * big deal I suppose. ++ */ ++ err = au_iigen_test(inode, au_sigen(sb)); ++ if (unlikely(err)) ++ goto out; ++#endif ++ ++ if (!isdir ++ || write_mask ++ || au_opt_test(au_mntflags(sb), DIRPERM1)) { ++ err = au_busy_or_stale(); ++ h_inode = au_h_iptr(inode, au_ibtop(inode)); ++ if (unlikely(!h_inode ++ || (h_inode->i_mode & S_IFMT) ++ != (inode->i_mode & S_IFMT))) ++ goto out; ++ ++ err = 0; ++ bindex = au_ibtop(inode); ++ br = au_sbr(sb, bindex); ++ err = h_permission(h_inode, mask, &br->br_path, br->br_perm); ++ if (write_mask ++ && !err ++ && !special_file(h_inode->i_mode)) { ++ /* test whether the upper writable branch exists */ ++ err = -EROFS; ++ for (; bindex >= 0; bindex--) ++ if (!au_br_rdonly(au_sbr(sb, bindex))) { ++ err = 0; ++ break; ++ } ++ } ++ goto out; ++ } ++ ++ /* non-write to dir */ ++ err = 0; ++ bbot = au_ibbot(inode); ++ for (bindex = au_ibtop(inode); !err && bindex <= bbot; bindex++) { ++ h_inode = au_h_iptr(inode, bindex); ++ if (h_inode) { ++ err = au_busy_or_stale(); ++ if (unlikely(!S_ISDIR(h_inode->i_mode))) ++ break; ++ ++ br = au_sbr(sb, bindex); ++ err = h_permission(h_inode, mask, &br->br_path, ++ br->br_perm); ++ } ++ } ++ ++out: ++ ii_read_unlock(inode); ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry *aufs_lookup(struct inode *dir, struct dentry *dentry, ++ unsigned int flags) ++{ ++ struct dentry *ret, *parent; ++ struct inode *inode; ++ struct super_block *sb; ++ int err, npositive; ++ ++ IMustLock(dir); ++ ++ /* todo: support rcu-walk? */ ++ ret = ERR_PTR(-ECHILD); ++ if (flags & LOOKUP_RCU) ++ goto out; ++ ++ ret = ERR_PTR(-ENAMETOOLONG); ++ if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) ++ goto out; ++ ++ sb = dir->i_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ ret = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_di_init(dentry); ++ ret = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_si; ++ ++ inode = NULL; ++ npositive = 0; /* suppress a warning */ ++ parent = dentry->d_parent; /* dir inode is locked */ ++ di_read_lock_parent(parent, AuLock_IR); ++ err = au_alive_dir(parent); ++ if (!err) ++ err = au_digen_test(parent, au_sigen(sb)); ++ if (!err) { ++ /* regardless LOOKUP_CREATE, always ALLOW_NEG */ ++ npositive = au_lkup_dentry(dentry, au_dbtop(parent), ++ AuLkup_ALLOW_NEG); ++ err = npositive; ++ } ++ di_read_unlock(parent, AuLock_IR); ++ ret = ERR_PTR(err); ++ if (unlikely(err < 0)) ++ goto out_unlock; ++ ++ if (npositive) { ++ inode = au_new_inode(dentry, /*must_new*/0); ++ if (IS_ERR(inode)) { ++ ret = (void *)inode; ++ inode = NULL; ++ goto out_unlock; ++ } ++ } ++ ++ if (inode) ++ atomic_inc(&inode->i_count); ++ ret = d_splice_alias(inode, dentry); ++#if 0 /* reserved for future use */ ++ if (unlikely(d_need_lookup(dentry))) { ++ spin_lock(&dentry->d_lock); ++ dentry->d_flags &= ~DCACHE_NEED_LOOKUP; ++ spin_unlock(&dentry->d_lock); ++ } else ++#endif ++ if (inode) { ++ if (!IS_ERR(ret)) { ++ iput(inode); ++ if (ret && ret != dentry) ++ ii_write_unlock(inode); ++ } else { ++ ii_write_unlock(inode); ++ iput(inode); ++ inode = NULL; ++ } ++ } ++ ++out_unlock: ++ di_write_unlock(dentry); ++out_si: ++ si_read_unlock(sb); ++out: ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * very dirty and complicated aufs ->atomic_open(). ++ * aufs_atomic_open() ++ * + au_aopen_or_create() ++ * + add_simple() ++ * + vfsub_atomic_open() ++ * + branch fs ->atomic_open() ++ * may call the actual 'open' for h_file ++ * + inc br_nfiles only if opened ++ * + au_aopen_no_open() or au_aopen_do_open() ++ * ++ * au_aopen_do_open() ++ * + finish_open() ++ * + au_do_aopen() ++ * + au_do_open() the body of all 'open' ++ * + au_do_open_nondir() ++ * set the passed h_file ++ * ++ * au_aopen_no_open() ++ * + finish_no_open() ++ */ ++ ++struct aopen_node { ++ struct hlist_bl_node hblist; ++ struct file *file, *h_file; ++}; ++ ++static int au_do_aopen(struct inode *inode, struct file *file) ++{ ++ struct hlist_bl_head *aopen; ++ struct hlist_bl_node *pos; ++ struct aopen_node *node; ++ struct au_do_open_args args = { ++ .aopen = 1, ++ .open = au_do_open_nondir ++ }; ++ ++ aopen = &au_sbi(inode->i_sb)->si_aopen; ++ hlist_bl_lock(aopen); ++ hlist_bl_for_each_entry(node, pos, aopen, hblist) ++ if (node->file == file) { ++ args.h_file = node->h_file; ++ break; ++ } ++ hlist_bl_unlock(aopen); ++ /* AuDebugOn(!args.h_file); */ ++ ++ return au_do_open(file, &args); ++} ++ ++static int au_aopen_do_open(struct file *file, struct dentry *dentry, ++ struct aopen_node *aopen_node) ++{ ++ int err; ++ struct hlist_bl_head *aopen; ++ ++ AuLabel(here); ++ aopen = &au_sbi(dentry->d_sb)->si_aopen; ++ au_hbl_add(&aopen_node->hblist, aopen); ++ err = finish_open(file, dentry, au_do_aopen); ++ au_hbl_del(&aopen_node->hblist, aopen); ++ /* AuDbgFile(file); */ ++ AuDbg("%pd%s%s\n", dentry, ++ (file->f_mode & FMODE_CREATED) ? " created" : "", ++ (file->f_mode & FMODE_OPENED) ? " opened" : ""); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_aopen_no_open(struct file *file, struct dentry *dentry) ++{ ++ int err; ++ ++ AuLabel(here); ++ dget(dentry); ++ err = finish_no_open(file, dentry); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int aufs_atomic_open(struct inode *dir, struct dentry *dentry, ++ struct file *file, unsigned int open_flag, ++ umode_t create_mode) ++{ ++ int err, did_open; ++ unsigned int lkup_flags; ++ aufs_bindex_t bindex; ++ struct super_block *sb; ++ struct dentry *parent, *d; ++ struct vfsub_aopen_args args = { ++ .open_flag = open_flag, ++ .create_mode = create_mode ++ }; ++ struct aopen_node aopen_node = { ++ .file = file ++ }; ++ ++ IMustLock(dir); ++ AuDbg("open_flag 0%o\n", open_flag); ++ AuDbgDentry(dentry); ++ ++ err = 0; ++ if (!au_di(dentry)) { ++ lkup_flags = LOOKUP_OPEN; ++ if (open_flag & O_CREAT) ++ lkup_flags |= LOOKUP_CREATE; ++ d = aufs_lookup(dir, dentry, lkup_flags); ++ if (IS_ERR(d)) { ++ err = PTR_ERR(d); ++ AuTraceErr(err); ++ goto out; ++ } else if (d) { ++ /* ++ * obsoleted dentry found. ++ * another error will be returned later. ++ */ ++ d_drop(d); ++ AuDbgDentry(d); ++ dput(d); ++ } ++ AuDbgDentry(dentry); ++ } ++ ++ if (d_is_positive(dentry) ++ || d_unhashed(dentry) ++ || d_unlinked(dentry) ++ || !(open_flag & O_CREAT)) { ++ err = au_aopen_no_open(file, dentry); ++ goto out; /* success */ ++ } ++ ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_GEN); ++ if (unlikely(err)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ parent = dentry->d_parent; /* dir is locked */ ++ di_write_lock_parent(parent); ++ err = au_lkup_dentry(dentry, /*btop*/0, AuLkup_ALLOW_NEG); ++ if (unlikely(err < 0)) ++ goto out_parent; ++ ++ AuDbgDentry(dentry); ++ if (d_is_positive(dentry)) { ++ err = au_aopen_no_open(file, dentry); ++ goto out_parent; /* success */ ++ } ++ ++ args.file = alloc_empty_file(file->f_flags, current_cred()); ++ err = PTR_ERR(args.file); ++ if (IS_ERR(args.file)) ++ goto out_parent; ++ ++ bindex = au_dbtop(dentry); ++ err = au_aopen_or_create(dir, dentry, &args); ++ AuTraceErr(err); ++ AuDbgFile(args.file); ++ file->f_mode = args.file->f_mode & ~FMODE_OPENED; ++ did_open = !!(args.file->f_mode & FMODE_OPENED); ++ if (!did_open) { ++ fput(args.file); ++ args.file = NULL; ++ } ++ di_write_unlock(parent); ++ di_write_unlock(dentry); ++ if (unlikely(err < 0)) { ++ if (args.file) ++ fput(args.file); ++ goto out_sb; ++ } ++ ++ if (!did_open) ++ err = au_aopen_no_open(file, dentry); ++ else { ++ aopen_node.h_file = args.file; ++ err = au_aopen_do_open(file, dentry, &aopen_node); ++ } ++ if (unlikely(err < 0)) { ++ if (args.file) ++ fput(args.file); ++ if (did_open) ++ au_lcnt_dec(&args.br->br_nfiles); ++ } ++ goto out_sb; /* success */ ++ ++out_parent: ++ di_write_unlock(parent); ++ di_write_unlock(dentry); ++out_sb: ++ si_read_unlock(sb); ++out: ++ AuTraceErr(err); ++ AuDbgFile(file); ++ return err; ++} ++ ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_wr_dir_cpup(struct dentry *dentry, struct dentry *parent, ++ const unsigned char add_entry, aufs_bindex_t bcpup, ++ aufs_bindex_t btop) ++{ ++ int err; ++ struct dentry *h_parent; ++ struct inode *h_dir; ++ ++ if (add_entry) ++ IMustLock(d_inode(parent)); ++ else ++ di_write_lock_parent(parent); ++ ++ err = 0; ++ if (!au_h_dptr(parent, bcpup)) { ++ if (btop > bcpup) ++ err = au_cpup_dirs(dentry, bcpup); ++ else if (btop < bcpup) ++ err = au_cpdown_dirs(dentry, bcpup); ++ else ++ BUG(); ++ } ++ if (!err && add_entry && !au_ftest_wrdir(add_entry, TMPFILE)) { ++ h_parent = au_h_dptr(parent, bcpup); ++ h_dir = d_inode(h_parent); ++ inode_lock_shared_nested(h_dir, AuLsc_I_PARENT); ++ err = au_lkup_neg(dentry, bcpup, /*wh*/0); ++ /* todo: no unlock here */ ++ inode_unlock_shared(h_dir); ++ ++ AuDbg("bcpup %d\n", bcpup); ++ if (!err) { ++ if (d_really_is_negative(dentry)) ++ au_set_h_dptr(dentry, btop, NULL); ++ au_update_dbrange(dentry, /*do_put_zero*/0); ++ } ++ } ++ ++ if (!add_entry) ++ di_write_unlock(parent); ++ if (!err) ++ err = bcpup; /* success */ ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * decide the branch and the parent dir where we will create a new entry. ++ * returns new bindex or an error. ++ * copyup the parent dir if needed. ++ */ ++int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry, ++ struct au_wr_dir_args *args) ++{ ++ int err; ++ unsigned int flags; ++ aufs_bindex_t bcpup, btop, src_btop; ++ const unsigned char add_entry ++ = au_ftest_wrdir(args->flags, ADD_ENTRY) ++ | au_ftest_wrdir(args->flags, TMPFILE); ++ struct super_block *sb; ++ struct dentry *parent; ++ struct au_sbinfo *sbinfo; ++ ++ sb = dentry->d_sb; ++ sbinfo = au_sbi(sb); ++ parent = dget_parent(dentry); ++ btop = au_dbtop(dentry); ++ bcpup = btop; ++ if (args->force_btgt < 0) { ++ if (src_dentry) { ++ src_btop = au_dbtop(src_dentry); ++ if (src_btop < btop) ++ bcpup = src_btop; ++ } else if (add_entry) { ++ flags = 0; ++ if (au_ftest_wrdir(args->flags, ISDIR)) ++ au_fset_wbr(flags, DIR); ++ err = AuWbrCreate(sbinfo, dentry, flags); ++ bcpup = err; ++ } ++ ++ if (bcpup < 0 || au_test_ro(sb, bcpup, d_inode(dentry))) { ++ if (add_entry) ++ err = AuWbrCopyup(sbinfo, dentry); ++ else { ++ if (!IS_ROOT(dentry)) { ++ di_read_lock_parent(parent, !AuLock_IR); ++ err = AuWbrCopyup(sbinfo, dentry); ++ di_read_unlock(parent, !AuLock_IR); ++ } else ++ err = AuWbrCopyup(sbinfo, dentry); ++ } ++ bcpup = err; ++ if (unlikely(err < 0)) ++ goto out; ++ } ++ } else { ++ bcpup = args->force_btgt; ++ AuDebugOn(au_test_ro(sb, bcpup, d_inode(dentry))); ++ } ++ ++ AuDbg("btop %d, bcpup %d\n", btop, bcpup); ++ err = bcpup; ++ if (bcpup == btop) ++ goto out; /* success */ ++ ++ /* copyup the new parent into the branch we process */ ++ err = au_wr_dir_cpup(dentry, parent, add_entry, bcpup, btop); ++ if (err >= 0) { ++ if (d_really_is_negative(dentry)) { ++ au_set_h_dptr(dentry, btop, NULL); ++ au_set_dbtop(dentry, bcpup); ++ au_set_dbbot(dentry, bcpup); ++ } ++ AuDebugOn(add_entry ++ && !au_ftest_wrdir(args->flags, TMPFILE) ++ && !au_h_dptr(dentry, bcpup)); ++ } ++ ++out: ++ dput(parent); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_pin_hdir_unlock(struct au_pin *p) ++{ ++ if (p->hdir) ++ au_hn_inode_unlock(p->hdir); ++} ++ ++int au_pin_hdir_lock(struct au_pin *p) ++{ ++ int err; ++ ++ err = 0; ++ if (!p->hdir) ++ goto out; ++ ++ /* even if an error happens later, keep this lock */ ++ au_hn_inode_lock_nested(p->hdir, p->lsc_hi); ++ ++ err = -EBUSY; ++ if (unlikely(p->hdir->hi_inode != d_inode(p->h_parent))) ++ goto out; ++ ++ err = 0; ++ if (p->h_dentry) ++ err = au_h_verify(p->h_dentry, p->udba, p->hdir->hi_inode, ++ p->h_parent, p->br); ++ ++out: ++ return err; ++} ++ ++int au_pin_hdir_relock(struct au_pin *p) ++{ ++ int err, i; ++ struct inode *h_i; ++ struct dentry *h_d[] = { ++ p->h_dentry, ++ p->h_parent ++ }; ++ ++ err = au_pin_hdir_lock(p); ++ if (unlikely(err)) ++ goto out; ++ ++ for (i = 0; !err && i < sizeof(h_d)/sizeof(*h_d); i++) { ++ if (!h_d[i]) ++ continue; ++ if (d_is_positive(h_d[i])) { ++ h_i = d_inode(h_d[i]); ++ err = !h_i->i_nlink; ++ } ++ } ++ ++out: ++ return err; ++} ++ ++static void au_pin_hdir_set_owner(struct au_pin *p, struct task_struct *task) ++{ ++ atomic_long_set(&p->hdir->hi_inode->i_rwsem.owner, (long)task); ++} ++ ++void au_pin_hdir_acquire_nest(struct au_pin *p) ++{ ++ if (p->hdir) { ++ rwsem_acquire_nest(&p->hdir->hi_inode->i_rwsem.dep_map, ++ p->lsc_hi, 0, NULL, _RET_IP_); ++ au_pin_hdir_set_owner(p, current); ++ } ++} ++ ++void au_pin_hdir_release(struct au_pin *p) ++{ ++ if (p->hdir) { ++ au_pin_hdir_set_owner(p, p->task); ++ rwsem_release(&p->hdir->hi_inode->i_rwsem.dep_map, _RET_IP_); ++ } ++} ++ ++struct dentry *au_pinned_h_parent(struct au_pin *pin) ++{ ++ if (pin && pin->parent) ++ return au_h_dptr(pin->parent, pin->bindex); ++ return NULL; ++} ++ ++void au_unpin(struct au_pin *p) ++{ ++ if (p->hdir) ++ au_pin_hdir_unlock(p); ++ if (p->h_mnt && au_ftest_pin(p->flags, MNT_WRITE)) ++ vfsub_mnt_drop_write(p->h_mnt); ++ if (!p->hdir) ++ return; ++ ++ if (!au_ftest_pin(p->flags, DI_LOCKED)) ++ di_read_unlock(p->parent, AuLock_IR); ++ iput(p->hdir->hi_inode); ++ dput(p->parent); ++ p->parent = NULL; ++ p->hdir = NULL; ++ p->h_mnt = NULL; ++ /* do not clear p->task */ ++} ++ ++int au_do_pin(struct au_pin *p) ++{ ++ int err; ++ struct super_block *sb; ++ struct inode *h_dir; ++ ++ err = 0; ++ sb = p->dentry->d_sb; ++ p->br = au_sbr(sb, p->bindex); ++ if (IS_ROOT(p->dentry)) { ++ if (au_ftest_pin(p->flags, MNT_WRITE)) { ++ p->h_mnt = au_br_mnt(p->br); ++ err = vfsub_mnt_want_write(p->h_mnt); ++ if (unlikely(err)) { ++ au_fclr_pin(p->flags, MNT_WRITE); ++ goto out_err; ++ } ++ } ++ goto out; ++ } ++ ++ p->h_dentry = NULL; ++ if (p->bindex <= au_dbbot(p->dentry)) ++ p->h_dentry = au_h_dptr(p->dentry, p->bindex); ++ ++ p->parent = dget_parent(p->dentry); ++ if (!au_ftest_pin(p->flags, DI_LOCKED)) ++ di_read_lock(p->parent, AuLock_IR, p->lsc_di); ++ ++ h_dir = NULL; ++ p->h_parent = au_h_dptr(p->parent, p->bindex); ++ p->hdir = au_hi(d_inode(p->parent), p->bindex); ++ if (p->hdir) ++ h_dir = p->hdir->hi_inode; ++ ++ /* ++ * udba case, or ++ * if DI_LOCKED is not set, then p->parent may be different ++ * and h_parent can be NULL. ++ */ ++ if (unlikely(!p->hdir || !h_dir || !p->h_parent)) { ++ err = -EBUSY; ++ if (!au_ftest_pin(p->flags, DI_LOCKED)) ++ di_read_unlock(p->parent, AuLock_IR); ++ dput(p->parent); ++ p->parent = NULL; ++ goto out_err; ++ } ++ ++ if (au_ftest_pin(p->flags, MNT_WRITE)) { ++ p->h_mnt = au_br_mnt(p->br); ++ err = vfsub_mnt_want_write(p->h_mnt); ++ if (unlikely(err)) { ++ au_fclr_pin(p->flags, MNT_WRITE); ++ if (!au_ftest_pin(p->flags, DI_LOCKED)) ++ di_read_unlock(p->parent, AuLock_IR); ++ dput(p->parent); ++ p->parent = NULL; ++ goto out_err; ++ } ++ } ++ ++ au_igrab(h_dir); ++ err = au_pin_hdir_lock(p); ++ if (!err) ++ goto out; /* success */ ++ ++ au_unpin(p); ++ ++out_err: ++ pr_err("err %d\n", err); ++ err = au_busy_or_stale(); ++out: ++ return err; ++} ++ ++void au_pin_init(struct au_pin *p, struct dentry *dentry, ++ aufs_bindex_t bindex, int lsc_di, int lsc_hi, ++ unsigned int udba, unsigned char flags) ++{ ++ p->dentry = dentry; ++ p->udba = udba; ++ p->lsc_di = lsc_di; ++ p->lsc_hi = lsc_hi; ++ p->flags = flags; ++ p->bindex = bindex; ++ ++ p->parent = NULL; ++ p->hdir = NULL; ++ p->h_mnt = NULL; ++ ++ p->h_dentry = NULL; ++ p->h_parent = NULL; ++ p->br = NULL; ++ p->task = current; ++} ++ ++int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int udba, unsigned char flags) ++{ ++ au_pin_init(pin, dentry, bindex, AuLsc_DI_PARENT, AuLsc_I_PARENT2, ++ udba, flags); ++ return au_do_pin(pin); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * ->setattr() and ->getattr() are called in various cases. ++ * chmod, stat: dentry is revalidated. ++ * fchmod, fstat: file and dentry are not revalidated, additionally they may be ++ * unhashed. ++ * for ->setattr(), ia->ia_file is passed from ftruncate only. ++ */ ++/* todo: consolidate with do_refresh() and simple_reval_dpath() */ ++int au_reval_for_attr(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ struct dentry *parent; ++ ++ err = 0; ++ if (au_digen_test(dentry, sigen)) { ++ parent = dget_parent(dentry); ++ di_read_lock_parent(parent, AuLock_IR); ++ err = au_refresh_dentry(dentry, parent); ++ di_read_unlock(parent, AuLock_IR); ++ dput(parent); ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_pin_and_icpup(struct dentry *dentry, struct iattr *ia, ++ struct au_icpup_args *a) ++{ ++ int err; ++ loff_t sz; ++ aufs_bindex_t btop, ibtop; ++ struct dentry *hi_wh, *parent; ++ struct inode *inode; ++ struct au_wr_dir_args wr_dir_args = { ++ .force_btgt = -1, ++ .flags = 0 ++ }; ++ ++ if (d_is_dir(dentry)) ++ au_fset_wrdir(wr_dir_args.flags, ISDIR); ++ /* plink or hi_wh() case */ ++ btop = au_dbtop(dentry); ++ inode = d_inode(dentry); ++ ibtop = au_ibtop(inode); ++ if (btop != ibtop && !au_test_ro(inode->i_sb, ibtop, inode)) ++ wr_dir_args.force_btgt = ibtop; ++ err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args); ++ if (unlikely(err < 0)) ++ goto out; ++ a->btgt = err; ++ if (err != btop) ++ au_fset_icpup(a->flags, DID_CPUP); ++ ++ err = 0; ++ a->pin_flags = AuPin_MNT_WRITE; ++ parent = NULL; ++ if (!IS_ROOT(dentry)) { ++ au_fset_pin(a->pin_flags, DI_LOCKED); ++ parent = dget_parent(dentry); ++ di_write_lock_parent(parent); ++ } ++ ++ err = au_pin(&a->pin, dentry, a->btgt, a->udba, a->pin_flags); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ sz = -1; ++ a->h_path.dentry = au_h_dptr(dentry, btop); ++ a->h_inode = d_inode(a->h_path.dentry); ++ if (ia && (ia->ia_valid & ATTR_SIZE)) { ++ inode_lock_shared_nested(a->h_inode, AuLsc_I_CHILD); ++ if (ia->ia_size < i_size_read(a->h_inode)) ++ sz = ia->ia_size; ++ inode_unlock_shared(a->h_inode); ++ } ++ ++ hi_wh = NULL; ++ if (au_ftest_icpup(a->flags, DID_CPUP) && d_unlinked(dentry)) { ++ hi_wh = au_hi_wh(inode, a->btgt); ++ if (!hi_wh) { ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = a->btgt, ++ .bsrc = -1, ++ .len = sz, ++ .pin = &a->pin ++ }; ++ err = au_sio_cpup_wh(&cpg, /*file*/NULL); ++ if (unlikely(err)) ++ goto out_unlock; ++ hi_wh = au_hi_wh(inode, a->btgt); ++ /* todo: revalidate hi_wh? */ ++ } ++ } ++ ++ if (parent) { ++ au_pin_set_parent_lflag(&a->pin, /*lflag*/0); ++ di_downgrade_lock(parent, AuLock_IR); ++ dput(parent); ++ parent = NULL; ++ } ++ if (!au_ftest_icpup(a->flags, DID_CPUP)) ++ goto out; /* success */ ++ ++ if (!d_unhashed(dentry)) { ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = a->btgt, ++ .bsrc = btop, ++ .len = sz, ++ .pin = &a->pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ err = au_sio_cpup_simple(&cpg); ++ if (!err) ++ a->h_path.dentry = au_h_dptr(dentry, a->btgt); ++ } else if (!hi_wh) ++ a->h_path.dentry = au_h_dptr(dentry, a->btgt); ++ else ++ a->h_path.dentry = hi_wh; /* do not dget here */ ++ ++out_unlock: ++ a->h_inode = d_inode(a->h_path.dentry); ++ if (!err) ++ goto out; /* success */ ++ au_unpin(&a->pin); ++out_parent: ++ if (parent) { ++ di_write_unlock(parent); ++ dput(parent); ++ } ++out: ++ if (!err) ++ inode_lock_nested(a->h_inode, AuLsc_I_CHILD); ++ return err; ++} ++ ++static int aufs_setattr(struct user_namespace *userns, struct dentry *dentry, ++ struct iattr *ia) ++{ ++ int err; ++ struct inode *inode, *delegated; ++ struct super_block *sb; ++ struct file *file; ++ struct au_icpup_args *a; ++ struct user_namespace *h_userns; ++ ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ ++ err = setattr_prepare(userns, dentry, ia); ++ if (unlikely(err)) ++ goto out; ++ ++ err = -ENOMEM; ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ if (ia->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) ++ ia->ia_valid &= ~ATTR_MODE; ++ ++ file = NULL; ++ sb = dentry->d_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out_kfree; ++ ++ if (ia->ia_valid & ATTR_FILE) { ++ /* currently ftruncate(2) only */ ++ AuDebugOn(!d_is_reg(dentry)); ++ file = ia->ia_file; ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1, ++ /*fi_lsc*/0); ++ if (unlikely(err)) ++ goto out_si; ++ ia->ia_file = au_hf_top(file); ++ a->udba = AuOpt_UDBA_NONE; ++ } else { ++ /* fchmod() doesn't pass ia_file */ ++ a->udba = au_opt_udba(sb); ++ di_write_lock_child(dentry); ++ /* no d_unlinked(), to set UDBA_NONE for root */ ++ if (d_unhashed(dentry)) ++ a->udba = AuOpt_UDBA_NONE; ++ if (a->udba != AuOpt_UDBA_NONE) { ++ AuDebugOn(IS_ROOT(dentry)); ++ err = au_reval_for_attr(dentry, au_sigen(sb)); ++ if (unlikely(err)) ++ goto out_dentry; ++ } ++ } ++ ++ err = au_pin_and_icpup(dentry, ia, a); ++ if (unlikely(err < 0)) ++ goto out_dentry; ++ if (au_ftest_icpup(a->flags, DID_CPUP)) { ++ ia->ia_file = NULL; ++ ia->ia_valid &= ~ATTR_FILE; ++ } ++ ++ a->h_path.mnt = au_sbr_mnt(sb, a->btgt); ++ if ((ia->ia_valid & (ATTR_MODE | ATTR_CTIME)) ++ == (ATTR_MODE | ATTR_CTIME)) { ++ err = security_path_chmod(&a->h_path, ia->ia_mode); ++ if (unlikely(err)) ++ goto out_unlock; ++ } else if ((ia->ia_valid & (ATTR_UID | ATTR_GID)) ++ && (ia->ia_valid & ATTR_CTIME)) { ++ err = security_path_chown(&a->h_path, ia->ia_uid, ia->ia_gid); ++ if (unlikely(err)) ++ goto out_unlock; ++ } ++ ++ if (ia->ia_valid & ATTR_SIZE) { ++ struct file *f; ++ ++ if (ia->ia_size < i_size_read(inode)) ++ /* unmap only */ ++ truncate_setsize(inode, ia->ia_size); ++ ++ f = NULL; ++ if (ia->ia_valid & ATTR_FILE) ++ f = ia->ia_file; ++ inode_unlock(a->h_inode); ++ err = vfsub_trunc(&a->h_path, ia->ia_size, ia->ia_valid, f); ++ inode_lock_nested(a->h_inode, AuLsc_I_CHILD); ++ } else { ++ delegated = NULL; ++ while (1) { ++ err = vfsub_notify_change(&a->h_path, ia, &delegated); ++ if (delegated) { ++ err = break_deleg_wait(&delegated); ++ if (!err) ++ continue; ++ } ++ break; ++ } ++ } ++ /* ++ * regardless aufs 'acl' option setting. ++ * why don't all acl-aware fs call this func from their ->setattr()? ++ */ ++ if (!err && (ia->ia_valid & ATTR_MODE)) { ++ h_userns = mnt_user_ns(a->h_path.mnt); ++ err = vfsub_acl_chmod(h_userns, a->h_inode, ia->ia_mode); ++ } ++ if (!err) ++ au_cpup_attr_changeable(inode); ++ ++out_unlock: ++ inode_unlock(a->h_inode); ++ au_unpin(&a->pin); ++ if (unlikely(err)) ++ au_update_dbtop(dentry); ++out_dentry: ++ di_write_unlock(dentry); ++ if (file) { ++ fi_write_unlock(file); ++ ia->ia_file = file; ++ ia->ia_valid |= ATTR_FILE; ++ } ++out_si: ++ si_read_unlock(sb); ++out_kfree: ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++#if IS_ENABLED(CONFIG_AUFS_XATTR) || IS_ENABLED(CONFIG_FS_POSIX_ACL) ++static int au_h_path_to_set_attr(struct dentry *dentry, ++ struct au_icpup_args *a, struct path *h_path) ++{ ++ int err; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ a->udba = au_opt_udba(sb); ++ /* no d_unlinked(), to set UDBA_NONE for root */ ++ if (d_unhashed(dentry)) ++ a->udba = AuOpt_UDBA_NONE; ++ if (a->udba != AuOpt_UDBA_NONE) { ++ AuDebugOn(IS_ROOT(dentry)); ++ err = au_reval_for_attr(dentry, au_sigen(sb)); ++ if (unlikely(err)) ++ goto out; ++ } ++ err = au_pin_and_icpup(dentry, /*ia*/NULL, a); ++ if (unlikely(err < 0)) ++ goto out; ++ ++ h_path->dentry = a->h_path.dentry; ++ h_path->mnt = au_sbr_mnt(sb, a->btgt); ++ ++out: ++ return err; ++} ++ ++ssize_t au_sxattr(struct dentry *dentry, struct inode *inode, ++ struct au_sxattr *arg) ++{ ++ int err; ++ struct path h_path; ++ struct super_block *sb; ++ struct au_icpup_args *a; ++ struct inode *h_inode; ++ struct user_namespace *h_userns; ++ ++ IMustLock(inode); ++ ++ err = -ENOMEM; ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out_kfree; ++ ++ h_path.dentry = NULL; /* silence gcc */ ++ di_write_lock_child(dentry); ++ err = au_h_path_to_set_attr(dentry, a, &h_path); ++ if (unlikely(err)) ++ goto out_di; ++ h_userns = mnt_user_ns(h_path.mnt); ++ ++ inode_unlock(a->h_inode); ++ switch (arg->type) { ++ case AU_XATTR_SET: ++ AuDebugOn(d_is_negative(h_path.dentry)); ++ err = vfsub_setxattr(h_userns, h_path.dentry, ++ arg->u.set.name, arg->u.set.value, ++ arg->u.set.size, arg->u.set.flags); ++ break; ++ case AU_ACL_SET: ++ err = -EOPNOTSUPP; ++ h_inode = d_inode(h_path.dentry); ++ if (h_inode->i_op->set_acl) { ++ /* this will call posix_acl_update_mode */ ++ err = h_inode->i_op->set_acl(h_userns, h_inode, ++ arg->u.acl_set.acl, ++ arg->u.acl_set.type); ++ } ++ break; ++ } ++ if (!err) ++ au_cpup_attr_timesizes(inode); ++ ++ au_unpin(&a->pin); ++ if (unlikely(err)) ++ au_update_dbtop(dentry); ++ ++out_di: ++ di_write_unlock(dentry); ++ si_read_unlock(sb); ++out_kfree: ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++#endif ++ ++static void au_refresh_iattr(struct inode *inode, struct kstat *st, ++ unsigned int nlink) ++{ ++ unsigned int n; ++ ++ inode->i_mode = st->mode; ++ /* don't i_[ug]id_write() here */ ++ inode->i_uid = st->uid; ++ inode->i_gid = st->gid; ++ inode->i_atime = st->atime; ++ inode->i_mtime = st->mtime; ++ inode->i_ctime = st->ctime; ++ ++ au_cpup_attr_nlink(inode, /*force*/0); ++ if (S_ISDIR(inode->i_mode)) { ++ n = inode->i_nlink; ++ n -= nlink; ++ n += st->nlink; ++ smp_mb(); /* for i_nlink */ ++ /* 0 can happen */ ++ set_nlink(inode, n); ++ } ++ ++ spin_lock(&inode->i_lock); ++ inode->i_blocks = st->blocks; ++ i_size_write(inode, st->size); ++ spin_unlock(&inode->i_lock); ++} ++ ++/* ++ * common routine for aufs_getattr() and au_getxattr(). ++ * returns zero or negative (an error). ++ * @dentry will be read-locked in success. ++ */ ++int au_h_path_getattr(struct dentry *dentry, struct inode *inode, int force, ++ struct path *h_path, int locked) ++{ ++ int err; ++ unsigned int mnt_flags, sigen; ++ unsigned char udba_none; ++ aufs_bindex_t bindex; ++ struct super_block *sb, *h_sb; ++ ++ h_path->mnt = NULL; ++ h_path->dentry = NULL; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ mnt_flags = au_mntflags(sb); ++ udba_none = !!au_opt_test(mnt_flags, UDBA_NONE); ++ ++ if (unlikely(locked)) ++ goto body; /* skip locking dinfo */ ++ ++ /* support fstat(2) */ ++ if (!d_unlinked(dentry) && !udba_none) { ++ sigen = au_sigen(sb); ++ err = au_digen_test(dentry, sigen); ++ if (!err) { ++ di_read_lock_child(dentry, AuLock_IR); ++ err = au_dbrange_test(dentry); ++ if (unlikely(err)) { ++ di_read_unlock(dentry, AuLock_IR); ++ goto out; ++ } ++ } else { ++ AuDebugOn(IS_ROOT(dentry)); ++ di_write_lock_child(dentry); ++ err = au_dbrange_test(dentry); ++ if (!err) ++ err = au_reval_for_attr(dentry, sigen); ++ if (!err) ++ di_downgrade_lock(dentry, AuLock_IR); ++ else { ++ di_write_unlock(dentry); ++ goto out; ++ } ++ } ++ } else ++ di_read_lock_child(dentry, AuLock_IR); ++ ++body: ++ if (!inode) { ++ inode = d_inode(dentry); ++ if (unlikely(!inode)) ++ goto out; ++ } ++ bindex = au_ibtop(inode); ++ h_path->mnt = au_sbr_mnt(sb, bindex); ++ h_sb = h_path->mnt->mnt_sb; ++ if (!force ++ && !au_test_fs_bad_iattr(h_sb) ++ && udba_none) ++ goto out; /* success */ ++ ++ if (au_dbtop(dentry) == bindex) ++ h_path->dentry = au_h_dptr(dentry, bindex); ++ else if (au_opt_test(mnt_flags, PLINK) && au_plink_test(inode)) { ++ h_path->dentry = au_plink_lkup(inode, bindex); ++ if (IS_ERR(h_path->dentry)) ++ /* pretending success */ ++ h_path->dentry = NULL; ++ else ++ dput(h_path->dentry); ++ } ++ ++out: ++ return err; ++} ++ ++static int aufs_getattr(struct user_namespace *userns, const struct path *path, ++ struct kstat *st, u32 request, unsigned int query) ++{ ++ int err; ++ unsigned char positive; ++ struct path h_path; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ dentry = path->dentry; ++ inode = d_inode(dentry); ++ sb = dentry->d_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out; ++ err = au_h_path_getattr(dentry, /*inode*/NULL, /*force*/0, &h_path, ++ /*locked*/0); ++ if (unlikely(err)) ++ goto out_si; ++ if (unlikely(!h_path.dentry)) ++ /* illegally overlapped or something */ ++ goto out_fill; /* pretending success */ ++ ++ positive = d_is_positive(h_path.dentry); ++ if (positive) ++ /* no vfsub version */ ++ err = vfs_getattr(&h_path, st, request, query); ++ if (!err) { ++ if (positive) ++ au_refresh_iattr(inode, st, ++ d_inode(h_path.dentry)->i_nlink); ++ goto out_fill; /* success */ ++ } ++ AuTraceErr(err); ++ goto out_di; ++ ++out_fill: ++ generic_fillattr(userns, inode, st); ++out_di: ++ di_read_unlock(dentry, AuLock_IR); ++out_si: ++ si_read_unlock(sb); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static const char *aufs_get_link(struct dentry *dentry, struct inode *inode, ++ struct delayed_call *done) ++{ ++ const char *ret; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ int err; ++ aufs_bindex_t bindex; ++ ++ ret = NULL; /* suppress a warning */ ++ err = -ECHILD; ++ if (!dentry) ++ goto out; ++ ++ err = aufs_read_lock(dentry, AuLock_IR | AuLock_GEN); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_d_hashed_positive(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ err = -EINVAL; ++ inode = d_inode(dentry); ++ bindex = au_ibtop(inode); ++ h_inode = au_h_iptr(inode, bindex); ++ if (unlikely(!h_inode->i_op->get_link)) ++ goto out_unlock; ++ ++ err = -EBUSY; ++ h_dentry = NULL; ++ if (au_dbtop(dentry) <= bindex) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry) ++ dget(h_dentry); ++ } ++ if (!h_dentry) { ++ h_dentry = d_find_any_alias(h_inode); ++ if (IS_ERR(h_dentry)) { ++ err = PTR_ERR(h_dentry); ++ goto out_unlock; ++ } ++ } ++ if (unlikely(!h_dentry)) ++ goto out_unlock; ++ ++ err = 0; ++ AuDbg("%ps\n", h_inode->i_op->get_link); ++ AuDbgDentry(h_dentry); ++ ret = vfs_get_link(h_dentry, done); ++ dput(h_dentry); ++ if (IS_ERR(ret)) ++ err = PTR_ERR(ret); ++ ++out_unlock: ++ aufs_read_unlock(dentry, AuLock_IR); ++out: ++ if (unlikely(err)) ++ ret = ERR_PTR(err); ++ AuTraceErrPtr(ret); ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_is_special(struct inode *inode) ++{ ++ return (inode->i_mode & (S_IFBLK | S_IFCHR | S_IFIFO | S_IFSOCK)); ++} ++ ++static int aufs_update_time(struct inode *inode, struct timespec64 *ts, ++ int flags) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct super_block *sb; ++ struct inode *h_inode; ++ struct vfsmount *h_mnt; ++ ++ sb = inode->i_sb; ++ WARN_ONCE((flags & S_ATIME) && !IS_NOATIME(inode), ++ "unexpected s_flags 0x%lx", sb->s_flags); ++ ++ /* mmap_sem might be acquired already, cf. aufs_mmap() */ ++ lockdep_off(); ++ si_read_lock(sb, AuLock_FLUSH); ++ ii_write_lock_child(inode); ++ ++ err = 0; ++ bindex = au_ibtop(inode); ++ h_inode = au_h_iptr(inode, bindex); ++ if (!au_test_ro(sb, bindex, inode)) { ++ h_mnt = au_sbr_mnt(sb, bindex); ++ err = vfsub_mnt_want_write(h_mnt); ++ if (!err) { ++ err = vfsub_update_time(h_inode, ts, flags); ++ vfsub_mnt_drop_write(h_mnt); ++ } ++ } else if (au_is_special(h_inode)) { ++ /* ++ * Never copy-up here. ++ * These special files may already be opened and used for ++ * communicating. If we copied it up, then the communication ++ * would be corrupted. ++ */ ++ AuWarn1("timestamps for i%lu are ignored " ++ "since it is on readonly branch (hi%lu).\n", ++ inode->i_ino, h_inode->i_ino); ++ } else if (flags & ~S_ATIME) { ++ err = -EIO; ++ AuIOErr1("unexpected flags 0x%x\n", flags); ++ AuDebugOn(1); ++ } ++ ++ if (!err) ++ au_cpup_attr_timesizes(inode); ++ ii_write_unlock(inode); ++ si_read_unlock(sb); ++ lockdep_on(); ++ ++ if (!err && (flags & S_VERSION)) ++ inode_inc_iversion(inode); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* no getattr version will be set by module.c:aufs_init() */ ++struct inode_operations aufs_iop_nogetattr[AuIop_Last], ++ aufs_iop[] = { ++ [AuIop_SYMLINK] = { ++ .permission = aufs_permission, ++#ifdef CONFIG_FS_POSIX_ACL ++ .get_acl = aufs_get_acl, ++ .set_acl = aufs_set_acl, /* unsupport for symlink? */ ++#endif ++ ++ .setattr = aufs_setattr, ++ .getattr = aufs_getattr, ++ ++#ifdef CONFIG_AUFS_XATTR ++ .listxattr = aufs_listxattr, ++#endif ++ ++ .get_link = aufs_get_link, ++ ++ /* .update_time = aufs_update_time */ ++ }, ++ [AuIop_DIR] = { ++ .create = aufs_create, ++ .lookup = aufs_lookup, ++ .link = aufs_link, ++ .unlink = aufs_unlink, ++ .symlink = aufs_symlink, ++ .mkdir = aufs_mkdir, ++ .rmdir = aufs_rmdir, ++ .mknod = aufs_mknod, ++ .rename = aufs_rename, ++ ++ .permission = aufs_permission, ++#ifdef CONFIG_FS_POSIX_ACL ++ .get_acl = aufs_get_acl, ++ .set_acl = aufs_set_acl, ++#endif ++ ++ .setattr = aufs_setattr, ++ .getattr = aufs_getattr, ++ ++#ifdef CONFIG_AUFS_XATTR ++ .listxattr = aufs_listxattr, ++#endif ++ ++ .update_time = aufs_update_time, ++ .atomic_open = aufs_atomic_open, ++ .tmpfile = aufs_tmpfile ++ }, ++ [AuIop_OTHER] = { ++ .permission = aufs_permission, ++#ifdef CONFIG_FS_POSIX_ACL ++ .get_acl = aufs_get_acl, ++ .set_acl = aufs_set_acl, ++#endif ++ ++ .setattr = aufs_setattr, ++ .getattr = aufs_getattr, ++ ++#ifdef CONFIG_AUFS_XATTR ++ .listxattr = aufs_listxattr, ++#endif ++ ++ .update_time = aufs_update_time ++ } ++}; +diff -Nurp linux-5.15.37/fs/aufs/i_op_del.c linux-5.15.37-aufs/fs/aufs/i_op_del.c +--- linux-5.15.37/fs/aufs/i_op_del.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/i_op_del.c 2022-04-08 20:22:30.614616573 +0300 +@@ -0,0 +1,509 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode operations (del entry) ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* ++ * decide if a new whiteout for @dentry is necessary or not. ++ * when it is necessary, prepare the parent dir for the upper branch whose ++ * branch index is @bcpup for creation. the actual creation of the whiteout will ++ * be done by caller. ++ * return value: ++ * 0: wh is unnecessary ++ * plus: wh is necessary ++ * minus: error ++ */ ++int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup) ++{ ++ int need_wh, err; ++ aufs_bindex_t btop; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ btop = au_dbtop(dentry); ++ if (*bcpup < 0) { ++ *bcpup = btop; ++ if (au_test_ro(sb, btop, d_inode(dentry))) { ++ err = AuWbrCopyup(au_sbi(sb), dentry); ++ *bcpup = err; ++ if (unlikely(err < 0)) ++ goto out; ++ } ++ } else ++ AuDebugOn(btop < *bcpup ++ || au_test_ro(sb, *bcpup, d_inode(dentry))); ++ AuDbg("bcpup %d, btop %d\n", *bcpup, btop); ++ ++ if (*bcpup != btop) { ++ err = au_cpup_dirs(dentry, *bcpup); ++ if (unlikely(err)) ++ goto out; ++ need_wh = 1; ++ } else { ++ struct au_dinfo *dinfo, *tmp; ++ ++ need_wh = -ENOMEM; ++ dinfo = au_di(dentry); ++ tmp = au_di_alloc(sb, AuLsc_DI_TMP); ++ if (tmp) { ++ au_di_cp(tmp, dinfo); ++ au_di_swap(tmp, dinfo); ++ /* returns the number of positive dentries */ ++ need_wh = au_lkup_dentry(dentry, btop + 1, ++ /* AuLkup_IGNORE_PERM */ 0); ++ au_di_swap(tmp, dinfo); ++ au_rw_write_unlock(&tmp->di_rwsem); ++ au_di_free(tmp); ++ } ++ } ++ AuDbg("need_wh %d\n", need_wh); ++ err = need_wh; ++ ++out: ++ return err; ++} ++ ++/* ++ * simple tests for the del-entry operations. ++ * following the checks in vfs, plus the parent-child relationship. ++ */ ++int au_may_del(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, int isdir) ++{ ++ int err; ++ umode_t h_mode; ++ struct dentry *h_dentry, *h_latest; ++ struct inode *h_inode; ++ struct path h_ppath; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct user_namespace *h_userns; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (d_really_is_positive(dentry)) { ++ err = -ENOENT; ++ if (unlikely(d_is_negative(h_dentry))) ++ goto out; ++ h_inode = d_inode(h_dentry); ++ if (unlikely(!h_inode->i_nlink)) ++ goto out; ++ ++ h_mode = h_inode->i_mode; ++ if (!isdir) { ++ err = -EISDIR; ++ if (unlikely(S_ISDIR(h_mode))) ++ goto out; ++ } else if (unlikely(!S_ISDIR(h_mode))) { ++ err = -ENOTDIR; ++ goto out; ++ } ++ } else { ++ /* rename(2) case */ ++ err = -EIO; ++ if (unlikely(d_is_positive(h_dentry))) ++ goto out; ++ } ++ ++ err = -ENOENT; ++ /* expected parent dir is locked */ ++ if (unlikely(h_parent != h_dentry->d_parent)) ++ goto out; ++ err = 0; ++ ++ /* ++ * rmdir a dir may break the consistency on some filesystem. ++ * let's try heavy test. ++ */ ++ err = -EACCES; ++ sb = dentry->d_sb; ++ br = au_sbr(sb, bindex); ++ h_userns = au_br_userns(br); ++ if (unlikely(!au_opt_test(au_mntflags(sb), DIRPERM1) ++ && au_test_h_perm(h_userns, d_inode(h_parent), ++ MAY_EXEC | MAY_WRITE))) ++ goto out; ++ ++ h_ppath.dentry = h_parent; ++ h_ppath.mnt = au_br_mnt(br); ++ h_latest = au_sio_lkup_one(h_userns, &dentry->d_name, &h_ppath); ++ err = -EIO; ++ if (IS_ERR(h_latest)) ++ goto out; ++ if (h_latest == h_dentry) ++ err = 0; ++ dput(h_latest); ++ ++out: ++ return err; ++} ++ ++/* ++ * decide the branch where we operate for @dentry. the branch index will be set ++ * @rbcpup. after deciding it, 'pin' it and store the timestamps of the parent ++ * dir for reverting. ++ * when a new whiteout is necessary, create it. ++ */ ++static struct dentry* ++lock_hdir_create_wh(struct dentry *dentry, int isdir, aufs_bindex_t *rbcpup, ++ struct au_dtime *dt, struct au_pin *pin) ++{ ++ struct dentry *wh_dentry; ++ struct super_block *sb; ++ struct path h_path; ++ int err, need_wh; ++ unsigned int udba; ++ aufs_bindex_t bcpup; ++ ++ need_wh = au_wr_dir_need_wh(dentry, isdir, rbcpup); ++ wh_dentry = ERR_PTR(need_wh); ++ if (unlikely(need_wh < 0)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ udba = au_opt_udba(sb); ++ bcpup = *rbcpup; ++ err = au_pin(pin, dentry, bcpup, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ h_path.dentry = au_pinned_h_parent(pin); ++ if (udba != AuOpt_UDBA_NONE ++ && au_dbtop(dentry) == bcpup) { ++ err = au_may_del(dentry, bcpup, h_path.dentry, isdir); ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_unpin; ++ } ++ ++ h_path.mnt = au_sbr_mnt(sb, bcpup); ++ au_dtime_store(dt, au_pinned_parent(pin), &h_path); ++ wh_dentry = NULL; ++ if (!need_wh) ++ goto out; /* success, no need to create whiteout */ ++ ++ wh_dentry = au_wh_create(dentry, bcpup, h_path.dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_unpin; ++ ++ /* returns with the parent is locked and wh_dentry is dget-ed */ ++ goto out; /* success */ ++ ++out_unpin: ++ au_unpin(pin); ++out: ++ return wh_dentry; ++} ++ ++/* ++ * when removing a dir, rename it to a unique temporary whiteout-ed name first ++ * in order to be revertible and save time for removing many child whiteouts ++ * under the dir. ++ * returns 1 when there are too many child whiteout and caller should remove ++ * them asynchronously. returns 0 when the number of children is enough small to ++ * remove now or the branch fs is a remote fs. ++ * otherwise return an error. ++ */ ++static int renwh_and_rmdir(struct dentry *dentry, aufs_bindex_t bindex, ++ struct au_nhash *whlist, struct inode *dir) ++{ ++ int rmdir_later, err, dirwh; ++ struct dentry *h_dentry; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ sb = dentry->d_sb; ++ SiMustAnyLock(sb); ++ h_dentry = au_h_dptr(dentry, bindex); ++ err = au_whtmp_ren(h_dentry, au_sbr(sb, bindex)); ++ if (unlikely(err)) ++ goto out; ++ ++ /* stop monitoring */ ++ inode = d_inode(dentry); ++ au_hn_free(au_hi(inode, bindex)); ++ ++ if (!au_test_fs_remote(h_dentry->d_sb)) { ++ dirwh = au_sbi(sb)->si_dirwh; ++ rmdir_later = (dirwh <= 1); ++ if (!rmdir_later) ++ rmdir_later = au_nhash_test_longer_wh(whlist, bindex, ++ dirwh); ++ if (rmdir_later) ++ return rmdir_later; ++ } ++ ++ err = au_whtmp_rmdir(dir, bindex, h_dentry, whlist); ++ if (unlikely(err)) { ++ AuIOErr("rmdir %pd, b%d failed, %d. ignored\n", ++ h_dentry, bindex, err); ++ err = 0; ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * final procedure for deleting a entry. ++ * maintain dentry and iattr. ++ */ ++static void epilog(struct inode *dir, struct dentry *dentry, ++ aufs_bindex_t bindex) ++{ ++ struct inode *inode; ++ ++ inode = d_inode(dentry); ++ d_drop(dentry); ++ inode->i_ctime = dir->i_ctime; ++ ++ au_dir_ts(dir, bindex); ++ inode_inc_iversion(dir); ++} ++ ++/* ++ * when an error happened, remove the created whiteout and revert everything. ++ */ ++static int do_revert(int err, struct inode *dir, aufs_bindex_t bindex, ++ aufs_bindex_t bwh, struct dentry *wh_dentry, ++ struct dentry *dentry, struct au_dtime *dt) ++{ ++ int rerr; ++ struct path h_path = { ++ .dentry = wh_dentry, ++ .mnt = au_sbr_mnt(dir->i_sb, bindex) ++ }; ++ ++ rerr = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path, dentry); ++ if (!rerr) { ++ au_set_dbwh(dentry, bwh); ++ au_dtime_revert(dt); ++ return 0; ++ } ++ ++ AuIOErr("%pd reverting whiteout failed(%d, %d)\n", dentry, err, rerr); ++ return -EIO; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int aufs_unlink(struct inode *dir, struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t bwh, bindex, btop; ++ struct inode *inode, *h_dir, *delegated; ++ struct dentry *parent, *wh_dentry; ++ /* to reduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct au_pin pin; ++ struct path h_path; ++ } *a; ++ ++ IMustLock(dir); ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_free; ++ err = au_d_hashed_positive(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ err = -EISDIR; ++ if (unlikely(d_is_dir(dentry))) ++ goto out_unlock; /* possible? */ ++ ++ btop = au_dbtop(dentry); ++ bwh = au_dbwh(dentry); ++ bindex = -1; ++ parent = dentry->d_parent; /* dir inode is locked */ ++ di_write_lock_parent(parent); ++ wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/0, &bindex, &a->dt, ++ &a->pin); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ a->h_path.mnt = au_sbr_mnt(dentry->d_sb, btop); ++ a->h_path.dentry = au_h_dptr(dentry, btop); ++ dget(a->h_path.dentry); ++ if (bindex == btop) { ++ h_dir = au_pinned_h_dir(&a->pin); ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, &a->h_path, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ } else { ++ /* dir inode is locked */ ++ h_dir = d_inode(wh_dentry->d_parent); ++ IMustLock(h_dir); ++ err = 0; ++ } ++ ++ if (!err) { ++ vfsub_drop_nlink(inode); ++ epilog(dir, dentry, bindex); ++ ++ /* update target timestamps */ ++ if (bindex == btop) { ++ vfsub_update_h_iattr(&a->h_path, /*did*/NULL); ++ /*ignore*/ ++ inode->i_ctime = d_inode(a->h_path.dentry)->i_ctime; ++ } else ++ /* todo: this timestamp may be reverted later */ ++ inode->i_ctime = h_dir->i_ctime; ++ goto out_unpin; /* success */ ++ } ++ ++ /* revert */ ++ if (wh_dentry) { ++ int rerr; ++ ++ rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry, ++ &a->dt); ++ if (rerr) ++ err = rerr; ++ } ++ ++out_unpin: ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++ dput(a->h_path.dentry); ++out_parent: ++ di_write_unlock(parent); ++out_unlock: ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ au_kfree_rcu(a); ++out: ++ return err; ++} ++ ++int aufs_rmdir(struct inode *dir, struct dentry *dentry) ++{ ++ int err, rmdir_later; ++ aufs_bindex_t bwh, bindex, btop; ++ struct inode *inode; ++ struct dentry *parent, *wh_dentry, *h_dentry; ++ struct au_whtmp_rmdir *args; ++ /* to reduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct au_pin pin; ++ } *a; ++ ++ IMustLock(dir); ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_free; ++ err = au_alive_dir(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ err = -ENOTDIR; ++ if (unlikely(!d_is_dir(dentry))) ++ goto out_unlock; /* possible? */ ++ ++ err = -ENOMEM; ++ args = au_whtmp_rmdir_alloc(dir->i_sb, GFP_NOFS); ++ if (unlikely(!args)) ++ goto out_unlock; ++ ++ parent = dentry->d_parent; /* dir inode is locked */ ++ di_write_lock_parent(parent); ++ err = au_test_empty(dentry, &args->whlist); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ btop = au_dbtop(dentry); ++ bwh = au_dbwh(dentry); ++ bindex = -1; ++ wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/1, &bindex, &a->dt, ++ &a->pin); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ h_dentry = au_h_dptr(dentry, btop); ++ dget(h_dentry); ++ rmdir_later = 0; ++ if (bindex == btop) { ++ err = renwh_and_rmdir(dentry, btop, &args->whlist, dir); ++ if (err > 0) { ++ rmdir_later = err; ++ err = 0; ++ } ++ } else { ++ /* stop monitoring */ ++ au_hn_free(au_hi(inode, btop)); ++ ++ /* dir inode is locked */ ++ IMustLock(d_inode(wh_dentry->d_parent)); ++ err = 0; ++ } ++ ++ if (!err) { ++ vfsub_dead_dir(inode); ++ au_set_dbdiropq(dentry, -1); ++ epilog(dir, dentry, bindex); ++ ++ if (rmdir_later) { ++ au_whtmp_kick_rmdir(dir, btop, h_dentry, args); ++ args = NULL; ++ } ++ ++ goto out_unpin; /* success */ ++ } ++ ++ /* revert */ ++ AuLabel(revert); ++ if (wh_dentry) { ++ int rerr; ++ ++ rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry, ++ &a->dt); ++ if (rerr) ++ err = rerr; ++ } ++ ++out_unpin: ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++ dput(h_dentry); ++out_parent: ++ di_write_unlock(parent); ++ if (args) ++ au_whtmp_rmdir_free(args); ++out_unlock: ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} +diff -Nurp linux-5.15.37/fs/aufs/i_op_ren.c linux-5.15.37-aufs/fs/aufs/i_op_ren.c +--- linux-5.15.37/fs/aufs/i_op_ren.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/i_op_ren.c 2022-04-08 20:22:30.614616573 +0300 +@@ -0,0 +1,1244 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode operation (rename entry) ++ * todo: this is crazy monster ++ */ ++ ++#include ++#include "aufs.h" ++ ++enum { AuSRC, AuDST, AuSrcDst }; ++enum { AuPARENT, AuCHILD, AuParentChild }; ++ ++#define AuRen_ISDIR_SRC 1 ++#define AuRen_ISDIR_DST (1 << 1) ++#define AuRen_ISSAMEDIR (1 << 2) ++#define AuRen_WHSRC (1 << 3) ++#define AuRen_WHDST (1 << 4) ++#define AuRen_MNT_WRITE (1 << 5) ++#define AuRen_DT_DSTDIR (1 << 6) ++#define AuRen_DIROPQ_SRC (1 << 7) ++#define AuRen_DIROPQ_DST (1 << 8) ++#define AuRen_DIRREN (1 << 9) ++#define AuRen_DROPPED_SRC (1 << 10) ++#define AuRen_DROPPED_DST (1 << 11) ++#define au_ftest_ren(flags, name) ((flags) & AuRen_##name) ++#define au_fset_ren(flags, name) \ ++ do { (flags) |= AuRen_##name; } while (0) ++#define au_fclr_ren(flags, name) \ ++ do { (flags) &= ~AuRen_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_DIRREN ++#undef AuRen_DIRREN ++#define AuRen_DIRREN 0 ++#endif ++ ++struct au_ren_args { ++ struct { ++ struct dentry *dentry, *h_dentry, *parent, *h_parent, ++ *wh_dentry; ++ struct inode *dir, *inode; ++ struct au_hinode *hdir, *hinode; ++ struct au_dtime dt[AuParentChild]; ++ aufs_bindex_t btop, bdiropq; ++ } sd[AuSrcDst]; ++ ++#define src_dentry sd[AuSRC].dentry ++#define src_dir sd[AuSRC].dir ++#define src_inode sd[AuSRC].inode ++#define src_h_dentry sd[AuSRC].h_dentry ++#define src_parent sd[AuSRC].parent ++#define src_h_parent sd[AuSRC].h_parent ++#define src_wh_dentry sd[AuSRC].wh_dentry ++#define src_hdir sd[AuSRC].hdir ++#define src_hinode sd[AuSRC].hinode ++#define src_h_dir sd[AuSRC].hdir->hi_inode ++#define src_dt sd[AuSRC].dt ++#define src_btop sd[AuSRC].btop ++#define src_bdiropq sd[AuSRC].bdiropq ++ ++#define dst_dentry sd[AuDST].dentry ++#define dst_dir sd[AuDST].dir ++#define dst_inode sd[AuDST].inode ++#define dst_h_dentry sd[AuDST].h_dentry ++#define dst_parent sd[AuDST].parent ++#define dst_h_parent sd[AuDST].h_parent ++#define dst_wh_dentry sd[AuDST].wh_dentry ++#define dst_hdir sd[AuDST].hdir ++#define dst_hinode sd[AuDST].hinode ++#define dst_h_dir sd[AuDST].hdir->hi_inode ++#define dst_dt sd[AuDST].dt ++#define dst_btop sd[AuDST].btop ++#define dst_bdiropq sd[AuDST].bdiropq ++ ++ struct dentry *h_trap; ++ struct au_branch *br; ++ struct path h_path; ++ struct au_nhash whlist; ++ aufs_bindex_t btgt, src_bwh; ++ ++ struct { ++ unsigned short auren_flags; ++ unsigned char flags; /* syscall parameter */ ++ unsigned char exchange; ++ } __packed; ++ ++ struct au_whtmp_rmdir *thargs; ++ struct dentry *h_dst; ++ struct au_hinode *h_root; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * functions for reverting. ++ * when an error happened in a single rename systemcall, we should revert ++ * everything as if nothing happened. ++ * we don't need to revert the copied-up/down the parent dir since they are ++ * harmless. ++ */ ++ ++#define RevertFailure(fmt, ...) do { \ ++ AuIOErr("revert failure: " fmt " (%d, %d)\n", \ ++ ##__VA_ARGS__, err, rerr); \ ++ err = -EIO; \ ++} while (0) ++ ++static void au_ren_do_rev_diropq(int err, struct au_ren_args *a, int idx) ++{ ++ int rerr; ++ struct dentry *d; ++#define src_or_dst(member) a->sd[idx].member ++ ++ d = src_or_dst(dentry); /* {src,dst}_dentry */ ++ au_hn_inode_lock_nested(src_or_dst(hinode), AuLsc_I_CHILD); ++ rerr = au_diropq_remove(d, a->btgt); ++ au_hn_inode_unlock(src_or_dst(hinode)); ++ au_set_dbdiropq(d, src_or_dst(bdiropq)); ++ if (rerr) ++ RevertFailure("remove diropq %pd", d); ++ ++#undef src_or_dst_ ++} ++ ++static void au_ren_rev_diropq(int err, struct au_ren_args *a) ++{ ++ if (au_ftest_ren(a->auren_flags, DIROPQ_SRC)) ++ au_ren_do_rev_diropq(err, a, AuSRC); ++ if (au_ftest_ren(a->auren_flags, DIROPQ_DST)) ++ au_ren_do_rev_diropq(err, a, AuDST); ++} ++ ++static void au_ren_rev_rename(int err, struct au_ren_args *a) ++{ ++ int rerr; ++ struct inode *delegated; ++ struct path h_ppath = { ++ .dentry = a->src_h_parent, ++ .mnt = a->h_path.mnt ++ }; ++ ++ a->h_path.dentry = vfsub_lkup_one(&a->src_dentry->d_name, &h_ppath); ++ rerr = PTR_ERR(a->h_path.dentry); ++ if (IS_ERR(a->h_path.dentry)) { ++ RevertFailure("lkup one %pd", a->src_dentry); ++ return; ++ } ++ ++ delegated = NULL; ++ rerr = vfsub_rename(a->dst_h_dir, ++ au_h_dptr(a->src_dentry, a->btgt), ++ a->src_h_dir, &a->h_path, &delegated, a->flags); ++ if (unlikely(rerr == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ d_drop(a->h_path.dentry); ++ dput(a->h_path.dentry); ++ /* au_set_h_dptr(a->src_dentry, a->btgt, NULL); */ ++ if (rerr) ++ RevertFailure("rename %pd", a->src_dentry); ++} ++ ++static void au_ren_rev_whtmp(int err, struct au_ren_args *a) ++{ ++ int rerr; ++ struct inode *delegated; ++ struct path h_ppath = { ++ .dentry = a->dst_h_parent, ++ .mnt = a->h_path.mnt ++ }; ++ ++ a->h_path.dentry = vfsub_lkup_one(&a->dst_dentry->d_name, &h_ppath); ++ rerr = PTR_ERR(a->h_path.dentry); ++ if (IS_ERR(a->h_path.dentry)) { ++ RevertFailure("lkup one %pd", a->dst_dentry); ++ return; ++ } ++ if (d_is_positive(a->h_path.dentry)) { ++ d_drop(a->h_path.dentry); ++ dput(a->h_path.dentry); ++ return; ++ } ++ ++ delegated = NULL; ++ rerr = vfsub_rename(a->dst_h_dir, a->h_dst, a->dst_h_dir, &a->h_path, ++ &delegated, a->flags); ++ if (unlikely(rerr == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ d_drop(a->h_path.dentry); ++ dput(a->h_path.dentry); ++ if (!rerr) ++ au_set_h_dptr(a->dst_dentry, a->btgt, dget(a->h_dst)); ++ else ++ RevertFailure("rename %pd", a->h_dst); ++} ++ ++static void au_ren_rev_whsrc(int err, struct au_ren_args *a) ++{ ++ int rerr; ++ ++ a->h_path.dentry = a->src_wh_dentry; ++ rerr = au_wh_unlink_dentry(a->src_h_dir, &a->h_path, a->src_dentry); ++ au_set_dbwh(a->src_dentry, a->src_bwh); ++ if (rerr) ++ RevertFailure("unlink %pd", a->src_wh_dentry); ++} ++#undef RevertFailure ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * when we have to copyup the renaming entry, do it with the rename-target name ++ * in order to minimize the cost (the later actual rename is unnecessary). ++ * otherwise rename it on the target branch. ++ */ ++static int au_ren_or_cpup(struct au_ren_args *a) ++{ ++ int err; ++ struct dentry *d; ++ struct inode *delegated; ++ ++ d = a->src_dentry; ++ if (au_dbtop(d) == a->btgt) { ++ a->h_path.dentry = a->dst_h_dentry; ++ AuDebugOn(au_dbtop(d) != a->btgt); ++ delegated = NULL; ++ err = vfsub_rename(a->src_h_dir, au_h_dptr(d, a->btgt), ++ a->dst_h_dir, &a->h_path, &delegated, ++ a->flags); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ } else ++ BUG(); ++ ++ if (!err && a->h_dst) ++ /* it will be set to dinfo later */ ++ dget(a->h_dst); ++ ++ return err; ++} ++ ++/* cf. aufs_rmdir() */ ++static int au_ren_del_whtmp(struct au_ren_args *a) ++{ ++ int err; ++ struct inode *dir; ++ ++ dir = a->dst_dir; ++ SiMustAnyLock(dir->i_sb); ++ if (!au_nhash_test_longer_wh(&a->whlist, a->btgt, ++ au_sbi(dir->i_sb)->si_dirwh) ++ || au_test_fs_remote(a->h_dst->d_sb)) { ++ err = au_whtmp_rmdir(dir, a->btgt, a->h_dst, &a->whlist); ++ if (unlikely(err)) ++ pr_warn("failed removing whtmp dir %pd (%d), " ++ "ignored.\n", a->h_dst, err); ++ } else { ++ au_nhash_wh_free(&a->thargs->whlist); ++ a->thargs->whlist = a->whlist; ++ a->whlist.nh_num = 0; ++ au_whtmp_kick_rmdir(dir, a->btgt, a->h_dst, a->thargs); ++ dput(a->h_dst); ++ a->thargs = NULL; ++ } ++ ++ return 0; ++} ++ ++/* make it 'opaque' dir. */ ++static int au_ren_do_diropq(struct au_ren_args *a, int idx) ++{ ++ int err; ++ struct dentry *d, *diropq; ++#define src_or_dst(member) a->sd[idx].member ++ ++ err = 0; ++ d = src_or_dst(dentry); /* {src,dst}_dentry */ ++ src_or_dst(bdiropq) = au_dbdiropq(d); ++ src_or_dst(hinode) = au_hi(src_or_dst(inode), a->btgt); ++ au_hn_inode_lock_nested(src_or_dst(hinode), AuLsc_I_CHILD); ++ diropq = au_diropq_create(d, a->btgt); ++ au_hn_inode_unlock(src_or_dst(hinode)); ++ if (IS_ERR(diropq)) ++ err = PTR_ERR(diropq); ++ else ++ dput(diropq); ++ ++#undef src_or_dst_ ++ return err; ++} ++ ++static int au_ren_diropq(struct au_ren_args *a) ++{ ++ int err; ++ unsigned char always; ++ struct dentry *d; ++ ++ err = 0; ++ d = a->dst_dentry; /* already renamed on the branch */ ++ always = !!au_opt_test(au_mntflags(d->d_sb), ALWAYS_DIROPQ); ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC) ++ && !au_ftest_ren(a->auren_flags, DIRREN) ++ && a->btgt != au_dbdiropq(a->src_dentry) ++ && (a->dst_wh_dentry ++ || a->btgt <= au_dbdiropq(d) ++ /* hide the lower to keep xino */ ++ /* the lowers may not be a dir, but we hide them anyway */ ++ || a->btgt < au_dbbot(d) ++ || always)) { ++ AuDbg("here\n"); ++ err = au_ren_do_diropq(a, AuSRC); ++ if (unlikely(err)) ++ goto out; ++ au_fset_ren(a->auren_flags, DIROPQ_SRC); ++ } ++ if (!a->exchange) ++ goto out; /* success */ ++ ++ d = a->src_dentry; /* already renamed on the branch */ ++ if (au_ftest_ren(a->auren_flags, ISDIR_DST) ++ && a->btgt != au_dbdiropq(a->dst_dentry) ++ && (a->btgt < au_dbdiropq(d) ++ || a->btgt < au_dbbot(d) ++ || always)) { ++ AuDbgDentry(a->src_dentry); ++ AuDbgDentry(a->dst_dentry); ++ err = au_ren_do_diropq(a, AuDST); ++ if (unlikely(err)) ++ goto out_rev_src; ++ au_fset_ren(a->auren_flags, DIROPQ_DST); ++ } ++ goto out; /* success */ ++ ++out_rev_src: ++ AuDbg("err %d, reverting src\n", err); ++ au_ren_rev_diropq(err, a); ++out: ++ return err; ++} ++ ++static int do_rename(struct au_ren_args *a) ++{ ++ int err; ++ struct dentry *d, *h_d; ++ ++ if (!a->exchange) { ++ /* prepare workqueue args for asynchronous rmdir */ ++ h_d = a->dst_h_dentry; ++ if (au_ftest_ren(a->auren_flags, ISDIR_DST) ++ /* && !au_ftest_ren(a->auren_flags, DIRREN) */ ++ && d_is_positive(h_d)) { ++ err = -ENOMEM; ++ a->thargs = au_whtmp_rmdir_alloc(a->src_dentry->d_sb, ++ GFP_NOFS); ++ if (unlikely(!a->thargs)) ++ goto out; ++ a->h_dst = dget(h_d); ++ } ++ ++ /* create whiteout for src_dentry */ ++ if (au_ftest_ren(a->auren_flags, WHSRC)) { ++ a->src_bwh = au_dbwh(a->src_dentry); ++ AuDebugOn(a->src_bwh >= 0); ++ a->src_wh_dentry = au_wh_create(a->src_dentry, a->btgt, ++ a->src_h_parent); ++ err = PTR_ERR(a->src_wh_dentry); ++ if (IS_ERR(a->src_wh_dentry)) ++ goto out_thargs; ++ } ++ ++ /* lookup whiteout for dentry */ ++ if (au_ftest_ren(a->auren_flags, WHDST)) { ++ h_d = au_wh_lkup(a->dst_h_parent, ++ &a->dst_dentry->d_name, a->br); ++ err = PTR_ERR(h_d); ++ if (IS_ERR(h_d)) ++ goto out_whsrc; ++ if (d_is_negative(h_d)) ++ dput(h_d); ++ else ++ a->dst_wh_dentry = h_d; ++ } ++ ++ /* rename dentry to tmpwh */ ++ if (a->thargs) { ++ err = au_whtmp_ren(a->dst_h_dentry, a->br); ++ if (unlikely(err)) ++ goto out_whdst; ++ ++ d = a->dst_dentry; ++ au_set_h_dptr(d, a->btgt, NULL); ++ err = au_lkup_neg(d, a->btgt, /*wh*/0); ++ if (unlikely(err)) ++ goto out_whtmp; ++ a->dst_h_dentry = au_h_dptr(d, a->btgt); ++ } ++ } ++ ++ BUG_ON(d_is_positive(a->dst_h_dentry) && a->src_btop != a->btgt); ++#if 0 /* debugging */ ++ BUG_ON(!au_ftest_ren(a->auren_flags, DIRREN) ++ && d_is_positive(a->dst_h_dentry) ++ && a->src_btop != a->btgt); ++#endif ++ ++ /* rename by vfs_rename or cpup */ ++ err = au_ren_or_cpup(a); ++ if (unlikely(err)) ++ /* leave the copied-up one */ ++ goto out_whtmp; ++ ++ /* make dir opaque */ ++ err = au_ren_diropq(a); ++ if (unlikely(err)) ++ goto out_rename; ++ ++ /* update target timestamps */ ++ if (a->exchange) { ++ AuDebugOn(au_dbtop(a->dst_dentry) != a->btgt); ++ a->h_path.dentry = au_h_dptr(a->dst_dentry, a->btgt); ++ vfsub_update_h_iattr(&a->h_path, /*did*/NULL); /*ignore*/ ++ a->dst_inode->i_ctime = d_inode(a->h_path.dentry)->i_ctime; ++ } ++ AuDebugOn(au_dbtop(a->src_dentry) != a->btgt); ++ a->h_path.dentry = au_h_dptr(a->src_dentry, a->btgt); ++ vfsub_update_h_iattr(&a->h_path, /*did*/NULL); /*ignore*/ ++ a->src_inode->i_ctime = d_inode(a->h_path.dentry)->i_ctime; ++ ++ if (!a->exchange) { ++ /* remove whiteout for dentry */ ++ if (a->dst_wh_dentry) { ++ a->h_path.dentry = a->dst_wh_dentry; ++ err = au_wh_unlink_dentry(a->dst_h_dir, &a->h_path, ++ a->dst_dentry); ++ if (unlikely(err)) ++ goto out_diropq; ++ } ++ ++ /* remove whtmp */ ++ if (a->thargs) ++ au_ren_del_whtmp(a); /* ignore this error */ ++ ++ au_fhsm_wrote(a->src_dentry->d_sb, a->btgt, /*force*/0); ++ } ++ err = 0; ++ goto out_success; ++ ++out_diropq: ++ au_ren_rev_diropq(err, a); ++out_rename: ++ au_ren_rev_rename(err, a); ++ dput(a->h_dst); ++out_whtmp: ++ if (a->thargs) ++ au_ren_rev_whtmp(err, a); ++out_whdst: ++ dput(a->dst_wh_dentry); ++ a->dst_wh_dentry = NULL; ++out_whsrc: ++ if (a->src_wh_dentry) ++ au_ren_rev_whsrc(err, a); ++out_success: ++ dput(a->src_wh_dentry); ++ dput(a->dst_wh_dentry); ++out_thargs: ++ if (a->thargs) { ++ dput(a->h_dst); ++ au_whtmp_rmdir_free(a->thargs); ++ a->thargs = NULL; ++ } ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * test if @dentry dir can be rename destination or not. ++ * success means, it is a logically empty dir. ++ */ ++static int may_rename_dstdir(struct dentry *dentry, struct au_nhash *whlist) ++{ ++ return au_test_empty(dentry, whlist); ++} ++ ++/* ++ * test if @a->src_dentry dir can be rename source or not. ++ * if it can, return 0. ++ * success means, ++ * - it is a logically empty dir. ++ * - or, it exists on writable branch and has no children including whiteouts ++ * on the lower branch unless DIRREN is on. ++ */ ++static int may_rename_srcdir(struct au_ren_args *a) ++{ ++ int err; ++ unsigned int rdhash; ++ aufs_bindex_t btop, btgt; ++ struct dentry *dentry; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ ++ dentry = a->src_dentry; ++ sb = dentry->d_sb; ++ sbinfo = au_sbi(sb); ++ if (au_opt_test(sbinfo->si_mntflags, DIRREN)) ++ au_fset_ren(a->auren_flags, DIRREN); ++ ++ btgt = a->btgt; ++ btop = au_dbtop(dentry); ++ if (btop != btgt) { ++ struct au_nhash whlist; ++ ++ SiMustAnyLock(sb); ++ rdhash = sbinfo->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, ++ dentry)); ++ err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_test_empty(dentry, &whlist); ++ au_nhash_wh_free(&whlist); ++ goto out; ++ } ++ ++ if (btop == au_dbtaildir(dentry)) ++ return 0; /* success */ ++ ++ err = au_test_empty_lower(dentry); ++ ++out: ++ if (err == -ENOTEMPTY) { ++ if (au_ftest_ren(a->auren_flags, DIRREN)) { ++ err = 0; ++ } else { ++ AuWarn1("renaming dir who has child(ren) on multiple " ++ "branches, is not supported\n"); ++ err = -EXDEV; ++ } ++ } ++ return err; ++} ++ ++/* side effect: sets whlist and h_dentry */ ++static int au_ren_may_dir(struct au_ren_args *a) ++{ ++ int err; ++ unsigned int rdhash; ++ struct dentry *d; ++ ++ d = a->dst_dentry; ++ SiMustAnyLock(d->d_sb); ++ ++ err = 0; ++ if (au_ftest_ren(a->auren_flags, ISDIR_DST) && a->dst_inode) { ++ rdhash = au_sbi(d->d_sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, d)); ++ err = au_nhash_alloc(&a->whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ ++ if (!a->exchange) { ++ au_set_dbtop(d, a->dst_btop); ++ err = may_rename_dstdir(d, &a->whlist); ++ au_set_dbtop(d, a->btgt); ++ } else ++ err = may_rename_srcdir(a); ++ } ++ a->dst_h_dentry = au_h_dptr(d, au_dbtop(d)); ++ if (unlikely(err)) ++ goto out; ++ ++ d = a->src_dentry; ++ a->src_h_dentry = au_h_dptr(d, au_dbtop(d)); ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC)) { ++ err = may_rename_srcdir(a); ++ if (unlikely(err)) { ++ au_nhash_wh_free(&a->whlist); ++ a->whlist.nh_num = 0; ++ } ++ } ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * simple tests for rename. ++ * following the checks in vfs, plus the parent-child relationship. ++ */ ++static int au_may_ren(struct au_ren_args *a) ++{ ++ int err, isdir; ++ struct inode *h_inode; ++ ++ if (a->src_btop == a->btgt) { ++ err = au_may_del(a->src_dentry, a->btgt, a->src_h_parent, ++ au_ftest_ren(a->auren_flags, ISDIR_SRC)); ++ if (unlikely(err)) ++ goto out; ++ err = -EINVAL; ++ if (unlikely(a->src_h_dentry == a->h_trap)) ++ goto out; ++ } ++ ++ err = 0; ++ if (a->dst_btop != a->btgt) ++ goto out; ++ ++ err = -ENOTEMPTY; ++ if (unlikely(a->dst_h_dentry == a->h_trap)) ++ goto out; ++ ++ err = -EIO; ++ isdir = !!au_ftest_ren(a->auren_flags, ISDIR_DST); ++ if (d_really_is_negative(a->dst_dentry)) { ++ if (d_is_negative(a->dst_h_dentry)) ++ err = au_may_add(a->dst_dentry, a->btgt, ++ a->dst_h_parent, isdir); ++ } else { ++ if (unlikely(d_is_negative(a->dst_h_dentry))) ++ goto out; ++ h_inode = d_inode(a->dst_h_dentry); ++ if (h_inode->i_nlink) ++ err = au_may_del(a->dst_dentry, a->btgt, ++ a->dst_h_parent, isdir); ++ } ++ ++out: ++ if (unlikely(err == -ENOENT || err == -EEXIST)) ++ err = -EIO; ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * locking order ++ * (VFS) ++ * - src_dir and dir by lock_rename() ++ * - inode if exists ++ * (aufs) ++ * - lock all ++ * + src_dentry and dentry by aufs_read_and_write_lock2() which calls, ++ * + si_read_lock ++ * + di_write_lock2_child() ++ * + di_write_lock_child() ++ * + ii_write_lock_child() ++ * + di_write_lock_child2() ++ * + ii_write_lock_child2() ++ * + src_parent and parent ++ * + di_write_lock_parent() ++ * + ii_write_lock_parent() ++ * + di_write_lock_parent2() ++ * + ii_write_lock_parent2() ++ * + lower src_dir and dir by vfsub_lock_rename() ++ * + verify the every relationships between child and parent. if any ++ * of them failed, unlock all and return -EBUSY. ++ */ ++static void au_ren_unlock(struct au_ren_args *a) ++{ ++ vfsub_unlock_rename(a->src_h_parent, a->src_hdir, ++ a->dst_h_parent, a->dst_hdir); ++ if (au_ftest_ren(a->auren_flags, DIRREN) ++ && a->h_root) ++ au_hn_inode_unlock(a->h_root); ++ if (au_ftest_ren(a->auren_flags, MNT_WRITE)) ++ vfsub_mnt_drop_write(au_br_mnt(a->br)); ++} ++ ++static int au_ren_lock(struct au_ren_args *a) ++{ ++ int err; ++ unsigned int udba; ++ ++ err = 0; ++ a->src_h_parent = au_h_dptr(a->src_parent, a->btgt); ++ a->src_hdir = au_hi(a->src_dir, a->btgt); ++ a->dst_h_parent = au_h_dptr(a->dst_parent, a->btgt); ++ a->dst_hdir = au_hi(a->dst_dir, a->btgt); ++ ++ err = vfsub_mnt_want_write(au_br_mnt(a->br)); ++ if (unlikely(err)) ++ goto out; ++ au_fset_ren(a->auren_flags, MNT_WRITE); ++ if (au_ftest_ren(a->auren_flags, DIRREN)) { ++ struct dentry *root; ++ struct inode *dir; ++ ++ /* ++ * sbinfo is already locked, so this ii_read_lock is ++ * unnecessary. but our debugging feature checks it. ++ */ ++ root = a->src_inode->i_sb->s_root; ++ if (root != a->src_parent && root != a->dst_parent) { ++ dir = d_inode(root); ++ ii_read_lock_parent3(dir); ++ a->h_root = au_hi(dir, a->btgt); ++ ii_read_unlock(dir); ++ au_hn_inode_lock_nested(a->h_root, AuLsc_I_PARENT3); ++ } ++ } ++ a->h_trap = vfsub_lock_rename(a->src_h_parent, a->src_hdir, ++ a->dst_h_parent, a->dst_hdir); ++ udba = au_opt_udba(a->src_dentry->d_sb); ++ if (unlikely(a->src_hdir->hi_inode != d_inode(a->src_h_parent) ++ || a->dst_hdir->hi_inode != d_inode(a->dst_h_parent))) ++ err = au_busy_or_stale(); ++ if (!err && au_dbtop(a->src_dentry) == a->btgt) ++ err = au_h_verify(a->src_h_dentry, udba, ++ d_inode(a->src_h_parent), a->src_h_parent, ++ a->br); ++ if (!err && au_dbtop(a->dst_dentry) == a->btgt) ++ err = au_h_verify(a->dst_h_dentry, udba, ++ d_inode(a->dst_h_parent), a->dst_h_parent, ++ a->br); ++ if (!err) ++ goto out; /* success */ ++ ++ err = au_busy_or_stale(); ++ au_ren_unlock(a); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_ren_refresh_dir(struct au_ren_args *a) ++{ ++ struct inode *dir; ++ ++ dir = a->dst_dir; ++ inode_inc_iversion(dir); ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC)) { ++ /* is this updating defined in POSIX? */ ++ au_cpup_attr_timesizes(a->src_inode); ++ au_cpup_attr_nlink(dir, /*force*/1); ++ } ++ au_dir_ts(dir, a->btgt); ++ ++ if (a->exchange) { ++ dir = a->src_dir; ++ inode_inc_iversion(dir); ++ if (au_ftest_ren(a->auren_flags, ISDIR_DST)) { ++ /* is this updating defined in POSIX? */ ++ au_cpup_attr_timesizes(a->dst_inode); ++ au_cpup_attr_nlink(dir, /*force*/1); ++ } ++ au_dir_ts(dir, a->btgt); ++ } ++ ++ if (au_ftest_ren(a->auren_flags, ISSAMEDIR)) ++ return; ++ ++ dir = a->src_dir; ++ inode_inc_iversion(dir); ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC)) ++ au_cpup_attr_nlink(dir, /*force*/1); ++ au_dir_ts(dir, a->btgt); ++} ++ ++static void au_ren_refresh(struct au_ren_args *a) ++{ ++ aufs_bindex_t bbot, bindex; ++ struct dentry *d, *h_d; ++ struct inode *i, *h_i; ++ struct super_block *sb; ++ ++ d = a->dst_dentry; ++ d_drop(d); ++ if (a->h_dst) ++ /* already dget-ed by au_ren_or_cpup() */ ++ au_set_h_dptr(d, a->btgt, a->h_dst); ++ ++ i = a->dst_inode; ++ if (i) { ++ if (!a->exchange) { ++ if (!au_ftest_ren(a->auren_flags, ISDIR_DST)) ++ vfsub_drop_nlink(i); ++ else { ++ vfsub_dead_dir(i); ++ au_cpup_attr_timesizes(i); ++ } ++ au_update_dbrange(d, /*do_put_zero*/1); ++ } else ++ au_cpup_attr_nlink(i, /*force*/1); ++ } else { ++ bbot = a->btgt; ++ for (bindex = au_dbtop(d); bindex < bbot; bindex++) ++ au_set_h_dptr(d, bindex, NULL); ++ bbot = au_dbbot(d); ++ for (bindex = a->btgt + 1; bindex <= bbot; bindex++) ++ au_set_h_dptr(d, bindex, NULL); ++ au_update_dbrange(d, /*do_put_zero*/0); ++ } ++ ++ if (a->exchange ++ || au_ftest_ren(a->auren_flags, DIRREN)) { ++ d_drop(a->src_dentry); ++ if (au_ftest_ren(a->auren_flags, DIRREN)) ++ au_set_dbwh(a->src_dentry, -1); ++ return; ++ } ++ ++ d = a->src_dentry; ++ au_set_dbwh(d, -1); ++ bbot = au_dbbot(d); ++ for (bindex = a->btgt + 1; bindex <= bbot; bindex++) { ++ h_d = au_h_dptr(d, bindex); ++ if (h_d) ++ au_set_h_dptr(d, bindex, NULL); ++ } ++ au_set_dbbot(d, a->btgt); ++ ++ sb = d->d_sb; ++ i = a->src_inode; ++ if (au_opt_test(au_mntflags(sb), PLINK) && au_plink_test(i)) ++ return; /* success */ ++ ++ bbot = au_ibbot(i); ++ for (bindex = a->btgt + 1; bindex <= bbot; bindex++) { ++ h_i = au_h_iptr(i, bindex); ++ if (h_i) { ++ au_xino_write(sb, bindex, h_i->i_ino, /*ino*/0); ++ /* ignore this error */ ++ au_set_h_iptr(i, bindex, NULL, 0); ++ } ++ } ++ au_set_ibbot(i, a->btgt); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* mainly for link(2) and rename(2) */ ++int au_wbr(struct dentry *dentry, aufs_bindex_t btgt) ++{ ++ aufs_bindex_t bdiropq, bwh; ++ struct dentry *parent; ++ struct au_branch *br; ++ ++ parent = dentry->d_parent; ++ IMustLock(d_inode(parent)); /* dir is locked */ ++ ++ bdiropq = au_dbdiropq(parent); ++ bwh = au_dbwh(dentry); ++ br = au_sbr(dentry->d_sb, btgt); ++ if (au_br_rdonly(br) ++ || (0 <= bdiropq && bdiropq < btgt) ++ || (0 <= bwh && bwh < btgt)) ++ btgt = -1; ++ ++ AuDbg("btgt %d\n", btgt); ++ return btgt; ++} ++ ++/* sets src_btop, dst_btop and btgt */ ++static int au_ren_wbr(struct au_ren_args *a) ++{ ++ int err; ++ struct au_wr_dir_args wr_dir_args = { ++ /* .force_btgt = -1, */ ++ .flags = AuWrDir_ADD_ENTRY ++ }; ++ ++ a->src_btop = au_dbtop(a->src_dentry); ++ a->dst_btop = au_dbtop(a->dst_dentry); ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC) ++ || au_ftest_ren(a->auren_flags, ISDIR_DST)) ++ au_fset_wrdir(wr_dir_args.flags, ISDIR); ++ wr_dir_args.force_btgt = a->src_btop; ++ if (a->dst_inode && a->dst_btop < a->src_btop) ++ wr_dir_args.force_btgt = a->dst_btop; ++ wr_dir_args.force_btgt = au_wbr(a->dst_dentry, wr_dir_args.force_btgt); ++ err = au_wr_dir(a->dst_dentry, a->src_dentry, &wr_dir_args); ++ a->btgt = err; ++ if (a->exchange) ++ au_update_dbtop(a->dst_dentry); ++ ++ return err; ++} ++ ++static void au_ren_dt(struct au_ren_args *a) ++{ ++ a->h_path.dentry = a->src_h_parent; ++ au_dtime_store(a->src_dt + AuPARENT, a->src_parent, &a->h_path); ++ if (!au_ftest_ren(a->auren_flags, ISSAMEDIR)) { ++ a->h_path.dentry = a->dst_h_parent; ++ au_dtime_store(a->dst_dt + AuPARENT, a->dst_parent, &a->h_path); ++ } ++ ++ au_fclr_ren(a->auren_flags, DT_DSTDIR); ++ if (!au_ftest_ren(a->auren_flags, ISDIR_SRC) ++ && !a->exchange) ++ return; ++ ++ a->h_path.dentry = a->src_h_dentry; ++ au_dtime_store(a->src_dt + AuCHILD, a->src_dentry, &a->h_path); ++ if (d_is_positive(a->dst_h_dentry)) { ++ au_fset_ren(a->auren_flags, DT_DSTDIR); ++ a->h_path.dentry = a->dst_h_dentry; ++ au_dtime_store(a->dst_dt + AuCHILD, a->dst_dentry, &a->h_path); ++ } ++} ++ ++static void au_ren_rev_dt(int err, struct au_ren_args *a) ++{ ++ struct dentry *h_d; ++ struct inode *h_inode; ++ ++ au_dtime_revert(a->src_dt + AuPARENT); ++ if (!au_ftest_ren(a->auren_flags, ISSAMEDIR)) ++ au_dtime_revert(a->dst_dt + AuPARENT); ++ ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC) && err != -EIO) { ++ h_d = a->src_dt[AuCHILD].dt_h_path.dentry; ++ h_inode = d_inode(h_d); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ au_dtime_revert(a->src_dt + AuCHILD); ++ inode_unlock(h_inode); ++ ++ if (au_ftest_ren(a->auren_flags, DT_DSTDIR)) { ++ h_d = a->dst_dt[AuCHILD].dt_h_path.dentry; ++ h_inode = d_inode(h_d); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ au_dtime_revert(a->dst_dt + AuCHILD); ++ inode_unlock(h_inode); ++ } ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int aufs_rename(struct user_namespace *userns, ++ struct inode *_src_dir, struct dentry *_src_dentry, ++ struct inode *_dst_dir, struct dentry *_dst_dentry, ++ unsigned int _flags) ++{ ++ int err, lock_flags; ++ void *rev; ++ /* reduce stack space */ ++ struct au_ren_args *a; ++ struct au_pin pin; ++ ++ AuDbg("%pd, %pd, 0x%x\n", _src_dentry, _dst_dentry, _flags); ++ IMustLock(_src_dir); ++ IMustLock(_dst_dir); ++ ++ err = -EINVAL; ++ if (unlikely(_flags & RENAME_WHITEOUT)) ++ goto out; ++ ++ err = -ENOMEM; ++ BUILD_BUG_ON(sizeof(*a) > PAGE_SIZE); ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ a->flags = _flags; ++ BUILD_BUG_ON(sizeof(a->exchange) == sizeof(u8) ++ && RENAME_EXCHANGE > U8_MAX); ++ a->exchange = _flags & RENAME_EXCHANGE; ++ a->src_dir = _src_dir; ++ a->src_dentry = _src_dentry; ++ a->src_inode = NULL; ++ if (d_really_is_positive(a->src_dentry)) ++ a->src_inode = d_inode(a->src_dentry); ++ a->src_parent = a->src_dentry->d_parent; /* dir inode is locked */ ++ a->dst_dir = _dst_dir; ++ a->dst_dentry = _dst_dentry; ++ a->dst_inode = NULL; ++ if (d_really_is_positive(a->dst_dentry)) ++ a->dst_inode = d_inode(a->dst_dentry); ++ a->dst_parent = a->dst_dentry->d_parent; /* dir inode is locked */ ++ if (a->dst_inode) { ++ /* ++ * if EXCHANGE && src is non-dir && dst is dir, ++ * dst is not locked. ++ */ ++ /* IMustLock(a->dst_inode); */ ++ au_igrab(a->dst_inode); ++ } ++ ++ err = -ENOTDIR; ++ lock_flags = AuLock_FLUSH | AuLock_NOPLM | AuLock_GEN; ++ if (d_is_dir(a->src_dentry)) { ++ au_fset_ren(a->auren_flags, ISDIR_SRC); ++ if (unlikely(!a->exchange ++ && d_really_is_positive(a->dst_dentry) ++ && !d_is_dir(a->dst_dentry))) ++ goto out_free; ++ lock_flags |= AuLock_DIRS; ++ } ++ if (a->dst_inode && d_is_dir(a->dst_dentry)) { ++ au_fset_ren(a->auren_flags, ISDIR_DST); ++ if (unlikely(!a->exchange ++ && d_really_is_positive(a->src_dentry) ++ && !d_is_dir(a->src_dentry))) ++ goto out_free; ++ lock_flags |= AuLock_DIRS; ++ } ++ err = aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry, ++ lock_flags); ++ if (unlikely(err)) ++ goto out_free; ++ ++ err = au_d_hashed_positive(a->src_dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ err = -ENOENT; ++ if (a->dst_inode) { ++ /* ++ * If it is a dir, VFS unhash it before this ++ * function. It means we cannot rely upon d_unhashed(). ++ */ ++ if (unlikely(!a->dst_inode->i_nlink)) ++ goto out_unlock; ++ if (!au_ftest_ren(a->auren_flags, ISDIR_DST)) { ++ err = au_d_hashed_positive(a->dst_dentry); ++ if (unlikely(err && !a->exchange)) ++ goto out_unlock; ++ } else if (unlikely(IS_DEADDIR(a->dst_inode))) ++ goto out_unlock; ++ } else if (unlikely(d_unhashed(a->dst_dentry))) ++ goto out_unlock; ++ ++ /* ++ * is it possible? ++ * yes, it happened (in linux-3.3-rcN) but I don't know why. ++ * there may exist a problem somewhere else. ++ */ ++ err = -EINVAL; ++ if (unlikely(d_inode(a->dst_parent) == d_inode(a->src_dentry))) ++ goto out_unlock; ++ ++ au_fset_ren(a->auren_flags, ISSAMEDIR); /* temporary */ ++ di_write_lock_parent(a->dst_parent); ++ ++ /* which branch we process */ ++ err = au_ren_wbr(a); ++ if (unlikely(err < 0)) ++ goto out_parent; ++ a->br = au_sbr(a->dst_dentry->d_sb, a->btgt); ++ a->h_path.mnt = au_br_mnt(a->br); ++ ++ /* are they available to be renamed */ ++ err = au_ren_may_dir(a); ++ if (unlikely(err)) ++ goto out_children; ++ ++ /* prepare the writable parent dir on the same branch */ ++ if (a->dst_btop == a->btgt) { ++ au_fset_ren(a->auren_flags, WHDST); ++ } else { ++ err = au_cpup_dirs(a->dst_dentry, a->btgt); ++ if (unlikely(err)) ++ goto out_children; ++ } ++ ++ err = 0; ++ if (!a->exchange) { ++ if (a->src_dir != a->dst_dir) { ++ /* ++ * this temporary unlock is safe, ++ * because both dir->i_mutex are locked. ++ */ ++ di_write_unlock(a->dst_parent); ++ di_write_lock_parent(a->src_parent); ++ err = au_wr_dir_need_wh(a->src_dentry, ++ au_ftest_ren(a->auren_flags, ++ ISDIR_SRC), ++ &a->btgt); ++ di_write_unlock(a->src_parent); ++ di_write_lock2_parent(a->src_parent, a->dst_parent, ++ /*isdir*/1); ++ au_fclr_ren(a->auren_flags, ISSAMEDIR); ++ } else ++ err = au_wr_dir_need_wh(a->src_dentry, ++ au_ftest_ren(a->auren_flags, ++ ISDIR_SRC), ++ &a->btgt); ++ } ++ if (unlikely(err < 0)) ++ goto out_children; ++ if (err) ++ au_fset_ren(a->auren_flags, WHSRC); ++ ++ /* cpup src */ ++ if (a->src_btop != a->btgt) { ++ err = au_pin(&pin, a->src_dentry, a->btgt, ++ au_opt_udba(a->src_dentry->d_sb), ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (!err) { ++ struct au_cp_generic cpg = { ++ .dentry = a->src_dentry, ++ .bdst = a->btgt, ++ .bsrc = a->src_btop, ++ .len = -1, ++ .pin = &pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ AuDebugOn(au_dbtop(a->src_dentry) != a->src_btop); ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&pin); ++ } ++ if (unlikely(err)) ++ goto out_children; ++ a->src_btop = a->btgt; ++ a->src_h_dentry = au_h_dptr(a->src_dentry, a->btgt); ++ if (!a->exchange) ++ au_fset_ren(a->auren_flags, WHSRC); ++ } ++ ++ /* cpup dst */ ++ if (a->exchange && a->dst_inode ++ && a->dst_btop != a->btgt) { ++ err = au_pin(&pin, a->dst_dentry, a->btgt, ++ au_opt_udba(a->dst_dentry->d_sb), ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (!err) { ++ struct au_cp_generic cpg = { ++ .dentry = a->dst_dentry, ++ .bdst = a->btgt, ++ .bsrc = a->dst_btop, ++ .len = -1, ++ .pin = &pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&pin); ++ } ++ if (unlikely(err)) ++ goto out_children; ++ a->dst_btop = a->btgt; ++ a->dst_h_dentry = au_h_dptr(a->dst_dentry, a->btgt); ++ } ++ ++ /* lock them all */ ++ err = au_ren_lock(a); ++ if (unlikely(err)) ++ /* leave the copied-up one */ ++ goto out_children; ++ ++ if (!a->exchange) { ++ if (!au_opt_test(au_mntflags(a->dst_dir->i_sb), UDBA_NONE)) ++ err = au_may_ren(a); ++ else if (unlikely(a->dst_dentry->d_name.len > AUFS_MAX_NAMELEN)) ++ err = -ENAMETOOLONG; ++ if (unlikely(err)) ++ goto out_hdir; ++ } ++ ++ /* store timestamps to be revertible */ ++ au_ren_dt(a); ++ ++ /* store dirren info */ ++ if (au_ftest_ren(a->auren_flags, DIRREN)) { ++ err = au_dr_rename(a->src_dentry, a->btgt, ++ &a->dst_dentry->d_name, &rev); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out_dt; ++ } ++ ++ /* here we go */ ++ err = do_rename(a); ++ if (unlikely(err)) ++ goto out_dirren; ++ ++ if (au_ftest_ren(a->auren_flags, DIRREN)) ++ au_dr_rename_fin(a->src_dentry, a->btgt, rev); ++ ++ /* update dir attributes */ ++ au_ren_refresh_dir(a); ++ ++ /* dput/iput all lower dentries */ ++ au_ren_refresh(a); ++ ++ goto out_hdir; /* success */ ++ ++out_dirren: ++ if (au_ftest_ren(a->auren_flags, DIRREN)) ++ au_dr_rename_rev(a->src_dentry, a->btgt, rev); ++out_dt: ++ au_ren_rev_dt(err, a); ++out_hdir: ++ au_ren_unlock(a); ++out_children: ++ au_nhash_wh_free(&a->whlist); ++ if (err && a->dst_inode && a->dst_btop != a->btgt) { ++ AuDbg("btop %d, btgt %d\n", a->dst_btop, a->btgt); ++ au_set_h_dptr(a->dst_dentry, a->btgt, NULL); ++ au_set_dbtop(a->dst_dentry, a->dst_btop); ++ } ++out_parent: ++ if (!err) { ++ if (d_unhashed(a->src_dentry)) ++ au_fset_ren(a->auren_flags, DROPPED_SRC); ++ if (d_unhashed(a->dst_dentry)) ++ au_fset_ren(a->auren_flags, DROPPED_DST); ++ if (!a->exchange) ++ d_move(a->src_dentry, a->dst_dentry); ++ else { ++ d_exchange(a->src_dentry, a->dst_dentry); ++ if (au_ftest_ren(a->auren_flags, DROPPED_DST)) ++ d_drop(a->dst_dentry); ++ } ++ if (au_ftest_ren(a->auren_flags, DROPPED_SRC)) ++ d_drop(a->src_dentry); ++ } else { ++ au_update_dbtop(a->dst_dentry); ++ if (!a->dst_inode) ++ d_drop(a->dst_dentry); ++ } ++ if (au_ftest_ren(a->auren_flags, ISSAMEDIR)) ++ di_write_unlock(a->dst_parent); ++ else ++ di_write_unlock2(a->src_parent, a->dst_parent); ++out_unlock: ++ aufs_read_and_write_unlock2(a->dst_dentry, a->src_dentry); ++out_free: ++ iput(a->dst_inode); ++ if (a->thargs) ++ au_whtmp_rmdir_free(a->thargs); ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} +diff -Nurp linux-5.15.37/fs/aufs/Kconfig linux-5.15.37-aufs/fs/aufs/Kconfig +--- linux-5.15.37/fs/aufs/Kconfig 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/Kconfig 2022-04-08 20:22:30.611616426 +0300 +@@ -0,0 +1,199 @@ ++# SPDX-License-Identifier: GPL-2.0 ++config AUFS_FS ++ bool "Aufs (Advanced multi layered unification filesystem) support" ++ help ++ Aufs is a stackable unification filesystem such as Unionfs, ++ which unifies several directories and provides a merged single ++ directory. ++ In the early days, aufs was entirely re-designed and ++ re-implemented Unionfs Version 1.x series. Introducing many ++ original ideas, approaches and improvements, it becomes totally ++ different from Unionfs while keeping the basic features. ++ ++if AUFS_FS ++choice ++ prompt "Maximum number of branches" ++ default AUFS_BRANCH_MAX_127 ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++config AUFS_BRANCH_MAX_127 ++ bool "127" ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++config AUFS_BRANCH_MAX_511 ++ bool "511" ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++config AUFS_BRANCH_MAX_1023 ++ bool "1023" ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++config AUFS_BRANCH_MAX_32767 ++ bool "32767" ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++endchoice ++ ++config AUFS_SBILIST ++ bool ++ depends on AUFS_MAGIC_SYSRQ || PROC_FS ++ default y ++ help ++ Automatic configuration for internal use. ++ When aufs supports Magic SysRq or /proc, enabled automatically. ++ ++config AUFS_HNOTIFY ++ bool "Detect direct branch access (bypassing aufs)" ++ help ++ If you want to modify files on branches directly, eg. bypassing aufs, ++ and want aufs to detect the changes of them fully, then enable this ++ option and use 'udba=notify' mount option. ++ Currently there is only one available configuration, "fsnotify". ++ It will have a negative impact to the performance. ++ See detail in aufs.5. ++ ++choice ++ prompt "method" if AUFS_HNOTIFY ++ default AUFS_HFSNOTIFY ++config AUFS_HFSNOTIFY ++ bool "fsnotify" ++ select FSNOTIFY ++endchoice ++ ++config AUFS_EXPORT ++ bool "NFS-exportable aufs" ++ depends on EXPORTFS = y ++ help ++ If you want to export your mounted aufs via NFS, then enable this ++ option. There are several requirements for this configuration. ++ See detail in aufs.5. ++ ++config AUFS_INO_T_64 ++ bool ++ depends on AUFS_EXPORT ++ depends on 64BIT && !(ALPHA || S390) ++ default y ++ help ++ Automatic configuration for internal use. ++ /* typedef unsigned long/int __kernel_ino_t */ ++ /* alpha and s390x are int */ ++ ++config AUFS_XATTR ++ bool "support for XATTR/EA (including Security Labels)" ++ help ++ If your branch fs supports XATTR/EA and you want to make them ++ available in aufs too, then enable this opsion and specify the ++ branch attributes for EA. ++ See detail in aufs.5. ++ ++config AUFS_FHSM ++ bool "File-based Hierarchical Storage Management" ++ help ++ Hierarchical Storage Management (or HSM) is a well-known feature ++ in the storage world. Aufs provides this feature as file-based. ++ with multiple branches. ++ These multiple branches are prioritized, ie. the topmost one ++ should be the fastest drive and be used heavily. ++ ++config AUFS_RDU ++ bool "Readdir in userspace" ++ help ++ Aufs has two methods to provide a merged view for a directory, ++ by a user-space library and by kernel-space natively. The latter ++ is always enabled but sometimes large and slow. ++ If you enable this option, install the library in aufs2-util ++ package, and set some environment variables for your readdir(3), ++ then the work will be handled in user-space which generally ++ shows better performance in most cases. ++ See detail in aufs.5. ++ ++config AUFS_DIRREN ++ bool "Workaround for rename(2)-ing a directory" ++ help ++ By default, aufs returns EXDEV error in renameing a dir who has ++ his child on the lower branch, since it is a bad idea to issue ++ rename(2) internally for every lower branch. But user may not ++ accept this behaviour. So here is a workaround to allow such ++ rename(2) and store some extra infromation on the writable ++ branch. Obviously this costs high (and I don't like it). ++ To use this feature, you need to enable this configuration AND ++ to specify the mount option `dirren.' ++ See details in aufs.5 and the design documents. ++ ++config AUFS_SHWH ++ bool "Show whiteouts" ++ help ++ If you want to make the whiteouts in aufs visible, then enable ++ this option and specify 'shwh' mount option. Although it may ++ sounds like philosophy or something, but in technically it ++ simply shows the name of whiteout with keeping its behaviour. ++ ++config AUFS_BR_RAMFS ++ bool "Ramfs (initramfs/rootfs) as an aufs branch" ++ help ++ If you want to use ramfs as an aufs branch fs, then enable this ++ option. Generally tmpfs is recommended. ++ Aufs prohibited them to be a branch fs by default, because ++ initramfs becomes unusable after switch_root or something ++ generally. If you sets initramfs as an aufs branch and boot your ++ system by switch_root, you will meet a problem easily since the ++ files in initramfs may be inaccessible. ++ Unless you are going to use ramfs as an aufs branch fs without ++ switch_root or something, leave it N. ++ ++config AUFS_BR_FUSE ++ bool "Fuse fs as an aufs branch" ++ depends on FUSE_FS ++ select AUFS_POLL ++ help ++ If you want to use fuse-based userspace filesystem as an aufs ++ branch fs, then enable this option. ++ It implements the internal poll(2) operation which is ++ implemented by fuse only (curretnly). ++ ++config AUFS_POLL ++ bool ++ help ++ Automatic configuration for internal use. ++ ++config AUFS_BR_HFSPLUS ++ bool "Hfsplus as an aufs branch" ++ depends on HFSPLUS_FS ++ default y ++ help ++ If you want to use hfsplus fs as an aufs branch fs, then enable ++ this option. This option introduces a small overhead at ++ copying-up a file on hfsplus. ++ ++config AUFS_BDEV_LOOP ++ bool ++ depends on BLK_DEV_LOOP ++ default y ++ help ++ Automatic configuration for internal use. ++ Convert =[ym] into =y. ++ ++config AUFS_DEBUG ++ bool "Debug aufs" ++ help ++ Enable this to compile aufs internal debug code. ++ It will have a negative impact to the performance. ++ ++config AUFS_MAGIC_SYSRQ ++ bool ++ depends on AUFS_DEBUG && MAGIC_SYSRQ ++ default y ++ help ++ Automatic configuration for internal use. ++ When aufs supports Magic SysRq, enabled automatically. ++endif +diff -Nurp linux-5.15.37/fs/aufs/lcnt.h linux-5.15.37-aufs/fs/aufs/lcnt.h +--- linux-5.15.37/fs/aufs/lcnt.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/lcnt.h 2022-04-08 20:22:30.614616573 +0300 +@@ -0,0 +1,173 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2018-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * simple long counter wrapper ++ */ ++ ++#ifndef __AUFS_LCNT_H__ ++#define __AUFS_LCNT_H__ ++ ++#ifdef __KERNEL__ ++ ++#include "debug.h" ++ ++#define AuLCntATOMIC 1 ++#define AuLCntPCPUCNT 2 ++/* ++ * why does percpu_refcount require extra synchronize_rcu()s in ++ * au_br_do_free() ++ */ ++#define AuLCntPCPUREF 3 ++ ++/* #define AuLCntChosen AuLCntATOMIC */ ++#define AuLCntChosen AuLCntPCPUCNT ++/* #define AuLCntChosen AuLCntPCPUREF */ ++ ++#if AuLCntChosen == AuLCntATOMIC ++#include ++ ++typedef atomic_long_t au_lcnt_t; ++ ++static inline int au_lcnt_init(au_lcnt_t *cnt, void *release __maybe_unused) ++{ ++ atomic_long_set(cnt, 0); ++ return 0; ++} ++ ++static inline void au_lcnt_wait_for_fin(au_lcnt_t *cnt __maybe_unused) ++{ ++ /* empty */ ++} ++ ++static inline void au_lcnt_fin(au_lcnt_t *cnt __maybe_unused, ++ int do_sync __maybe_unused) ++{ ++ /* empty */ ++} ++ ++static inline void au_lcnt_inc(au_lcnt_t *cnt) ++{ ++ atomic_long_inc(cnt); ++} ++ ++static inline void au_lcnt_dec(au_lcnt_t *cnt) ++{ ++ atomic_long_dec(cnt); ++} ++ ++static inline long au_lcnt_read(au_lcnt_t *cnt, int do_rev __maybe_unused) ++{ ++ return atomic_long_read(cnt); ++} ++#endif ++ ++#if AuLCntChosen == AuLCntPCPUCNT ++#include ++ ++typedef struct percpu_counter au_lcnt_t; ++ ++static inline int au_lcnt_init(au_lcnt_t *cnt, void *release __maybe_unused) ++{ ++ return percpu_counter_init(cnt, 0, GFP_NOFS); ++} ++ ++static inline void au_lcnt_wait_for_fin(au_lcnt_t *cnt __maybe_unused) ++{ ++ /* empty */ ++} ++ ++static inline void au_lcnt_fin(au_lcnt_t *cnt, int do_sync __maybe_unused) ++{ ++ percpu_counter_destroy(cnt); ++} ++ ++static inline void au_lcnt_inc(au_lcnt_t *cnt) ++{ ++ percpu_counter_inc(cnt); ++} ++ ++static inline void au_lcnt_dec(au_lcnt_t *cnt) ++{ ++ percpu_counter_dec(cnt); ++} ++ ++static inline long au_lcnt_read(au_lcnt_t *cnt, int do_rev __maybe_unused) ++{ ++ s64 n; ++ ++ n = percpu_counter_sum(cnt); ++ BUG_ON(n < 0); ++ if (LONG_MAX != LLONG_MAX ++ && n > LONG_MAX) ++ AuWarn1("%s\n", "wrap-around"); ++ ++ return n; ++} ++#endif ++ ++#if AuLCntChosen == AuLCntPCPUREF ++#include ++ ++typedef struct percpu_ref au_lcnt_t; ++ ++static inline int au_lcnt_init(au_lcnt_t *cnt, percpu_ref_func_t *release) ++{ ++ if (!release) ++ release = percpu_ref_exit; ++ return percpu_ref_init(cnt, release, /*percpu mode*/0, GFP_NOFS); ++} ++ ++static inline void au_lcnt_wait_for_fin(au_lcnt_t *cnt __maybe_unused) ++{ ++ synchronize_rcu(); ++} ++ ++static inline void au_lcnt_fin(au_lcnt_t *cnt, int do_sync) ++{ ++ percpu_ref_kill(cnt); ++ if (do_sync) ++ au_lcnt_wait_for_fin(cnt); ++} ++ ++static inline void au_lcnt_inc(au_lcnt_t *cnt) ++{ ++ percpu_ref_get(cnt); ++} ++ ++static inline void au_lcnt_dec(au_lcnt_t *cnt) ++{ ++ percpu_ref_put(cnt); ++} ++ ++/* ++ * avoid calling this func as possible. ++ */ ++static inline long au_lcnt_read(au_lcnt_t *cnt, int do_rev) ++{ ++ long l; ++ ++ percpu_ref_switch_to_atomic_sync(cnt); ++ l = atomic_long_read(&cnt->count); ++ if (do_rev) ++ percpu_ref_switch_to_percpu(cnt); ++ ++ /* percpu_ref is initialized by 1 instead of 0 */ ++ return l - 1; ++} ++#endif ++ ++#ifdef CONFIG_AUFS_DEBUG ++#define AuLCntZero(val) do { \ ++ long l = val; \ ++ if (l) \ ++ AuDbg("%s = %ld\n", #val, l); \ ++} while (0) ++#else ++#define AuLCntZero(val) do {} while (0) ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_LCNT_H__ */ +diff -Nurp linux-5.15.37/fs/aufs/loop.c linux-5.15.37-aufs/fs/aufs/loop.c +--- linux-5.15.37/fs/aufs/loop.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/loop.c 2022-04-08 20:22:30.614616573 +0300 +@@ -0,0 +1,135 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * support for loopback block device as a branch ++ */ ++ ++#include "aufs.h" ++ ++/* added into drivers/block/loop.c */ ++static struct file *(*backing_file_func)(struct super_block *sb); ++ ++/* ++ * test if two lower dentries have overlapping branches. ++ */ ++int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_adding) ++{ ++ struct super_block *h_sb; ++ struct file *backing_file; ++ ++ if (unlikely(!backing_file_func)) { ++ /* don't load "loop" module here */ ++ backing_file_func = symbol_get(loop_backing_file); ++ if (unlikely(!backing_file_func)) ++ /* "loop" module is not loaded */ ++ return 0; ++ } ++ ++ h_sb = h_adding->d_sb; ++ backing_file = backing_file_func(h_sb); ++ if (!backing_file) ++ return 0; ++ ++ h_adding = backing_file->f_path.dentry; ++ /* ++ * h_adding can be local NFS. ++ * in this case aufs cannot detect the loop. ++ */ ++ if (unlikely(h_adding->d_sb == sb)) ++ return 1; ++ return !!au_test_subdir(h_adding, sb->s_root); ++} ++ ++/* true if a kernel thread named 'loop[0-9].*' accesses a file */ ++int au_test_loopback_kthread(void) ++{ ++ int ret; ++ struct task_struct *tsk = current; ++ char c, comm[sizeof(tsk->comm)]; ++ ++ ret = 0; ++ if (tsk->flags & PF_KTHREAD) { ++ get_task_comm(comm, tsk); ++ c = comm[4]; ++ ret = ('0' <= c && c <= '9' ++ && !strncmp(comm, "loop", 4)); ++ } ++ ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define au_warn_loopback_step 16 ++static int au_warn_loopback_nelem = au_warn_loopback_step; ++static unsigned long *au_warn_loopback_array; ++ ++void au_warn_loopback(struct super_block *h_sb) ++{ ++ int i, new_nelem; ++ unsigned long *a, magic; ++ static DEFINE_SPINLOCK(spin); ++ ++ magic = h_sb->s_magic; ++ spin_lock(&spin); ++ a = au_warn_loopback_array; ++ for (i = 0; i < au_warn_loopback_nelem && *a; i++) ++ if (a[i] == magic) { ++ spin_unlock(&spin); ++ return; ++ } ++ ++ /* h_sb is new to us, print it */ ++ if (i < au_warn_loopback_nelem) { ++ a[i] = magic; ++ goto pr; ++ } ++ ++ /* expand the array */ ++ new_nelem = au_warn_loopback_nelem + au_warn_loopback_step; ++ a = au_kzrealloc(au_warn_loopback_array, ++ au_warn_loopback_nelem * sizeof(unsigned long), ++ new_nelem * sizeof(unsigned long), GFP_ATOMIC, ++ /*may_shrink*/0); ++ if (a) { ++ au_warn_loopback_nelem = new_nelem; ++ au_warn_loopback_array = a; ++ a[i] = magic; ++ goto pr; ++ } ++ ++ spin_unlock(&spin); ++ AuWarn1("realloc failed, ignored\n"); ++ return; ++ ++pr: ++ spin_unlock(&spin); ++ pr_warn("you may want to try another patch for loopback file " ++ "on %s(0x%lx) branch\n", au_sbtype(h_sb), magic); ++} ++ ++int au_loopback_init(void) ++{ ++ int err; ++ struct super_block *sb __maybe_unused; ++ ++ BUILD_BUG_ON(sizeof(sb->s_magic) != sizeof(*au_warn_loopback_array)); ++ ++ err = 0; ++ au_warn_loopback_array = kcalloc(au_warn_loopback_step, ++ sizeof(unsigned long), GFP_NOFS); ++ if (unlikely(!au_warn_loopback_array)) ++ err = -ENOMEM; ++ ++ return err; ++} ++ ++void au_loopback_fin(void) ++{ ++ if (backing_file_func) ++ symbol_put(loop_backing_file); ++ au_kfree_try_rcu(au_warn_loopback_array); ++} +diff -Nurp linux-5.15.37/fs/aufs/loop.h linux-5.15.37-aufs/fs/aufs/loop.h +--- linux-5.15.37/fs/aufs/loop.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/loop.h 2022-04-08 20:22:30.614616573 +0300 +@@ -0,0 +1,42 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * support for loopback mount as a branch ++ */ ++ ++#ifndef __AUFS_LOOP_H__ ++#define __AUFS_LOOP_H__ ++ ++#ifdef __KERNEL__ ++ ++struct dentry; ++struct super_block; ++ ++#ifdef CONFIG_AUFS_BDEV_LOOP ++/* drivers/block/loop.c */ ++struct file *loop_backing_file(struct super_block *sb); ++ ++/* loop.c */ ++int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_adding); ++int au_test_loopback_kthread(void); ++void au_warn_loopback(struct super_block *h_sb); ++ ++int au_loopback_init(void); ++void au_loopback_fin(void); ++#else ++AuStub(struct file *, loop_backing_file, return NULL, struct super_block *sb) ++ ++AuStubInt0(au_test_loopback_overlap, struct super_block *sb, ++ struct dentry *h_adding) ++AuStubInt0(au_test_loopback_kthread, void) ++AuStubVoid(au_warn_loopback, struct super_block *h_sb) ++ ++AuStubInt0(au_loopback_init, void) ++AuStubVoid(au_loopback_fin, void) ++#endif /* BLK_DEV_LOOP */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_LOOP_H__ */ +diff -Nurp linux-5.15.37/fs/aufs/magic.mk linux-5.15.37-aufs/fs/aufs/magic.mk +--- linux-5.15.37/fs/aufs/magic.mk 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/magic.mk 2022-04-08 20:22:30.614616573 +0300 +@@ -0,0 +1,31 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++# defined in ${srctree}/fs/fuse/inode.c ++# tristate ++ifdef CONFIG_FUSE_FS ++ccflags-y += -DFUSE_SUPER_MAGIC=0x65735546 ++endif ++ ++# defined in ${srctree}/fs/xfs/xfs_sb.h ++# tristate ++ifdef CONFIG_XFS_FS ++ccflags-y += -DXFS_SB_MAGIC=0x58465342 ++endif ++ ++# defined in ${srctree}/fs/configfs/mount.c ++# tristate ++ifdef CONFIG_CONFIGFS_FS ++ccflags-y += -DCONFIGFS_MAGIC=0x62656570 ++endif ++ ++# defined in ${srctree}/fs/ubifs/ubifs.h ++# tristate ++ifdef CONFIG_UBIFS_FS ++ccflags-y += -DUBIFS_SUPER_MAGIC=0x24051905 ++endif ++ ++# defined in ${srctree}/fs/hfsplus/hfsplus_raw.h ++# tristate ++ifdef CONFIG_HFSPLUS_FS ++ccflags-y += -DHFSPLUS_SUPER_MAGIC=0x482b ++endif +diff -Nurp linux-5.15.37/fs/aufs/Makefile linux-5.15.37-aufs/fs/aufs/Makefile +--- linux-5.15.37/fs/aufs/Makefile 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/Makefile 2022-04-08 20:22:30.611616426 +0300 +@@ -0,0 +1,39 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++include ${srctree}/${src}/magic.mk ++-include ${srctree}/${src}/priv_def.mk ++ ++# cf. include/linux/kernel.h ++# enable pr_debug ++ccflags-y += -DDEBUG ++# sparse requires the full pathname ++ccflags-y += -include ${srctree}/include/uapi/linux/aufs_type.h ++ ++obj-$(CONFIG_AUFS_FS) += aufs.o ++aufs-y := module.o sbinfo.o super.o branch.o xino.o sysaufs.o opts.o fsctx.o \ ++ wkq.o vfsub.o dcsub.o \ ++ cpup.o whout.o wbr_policy.o \ ++ dinfo.o dentry.o \ ++ dynop.o \ ++ finfo.o file.o f_op.o \ ++ dir.o vdir.o \ ++ iinfo.o inode.o i_op.o i_op_add.o i_op_del.o i_op_ren.o \ ++ mvdown.o ioctl.o ++ ++# all are boolean ++aufs-$(CONFIG_PROC_FS) += procfs.o plink.o ++aufs-$(CONFIG_SYSFS) += sysfs.o ++aufs-$(CONFIG_DEBUG_FS) += dbgaufs.o ++aufs-$(CONFIG_AUFS_BDEV_LOOP) += loop.o ++aufs-$(CONFIG_AUFS_HNOTIFY) += hnotify.o ++aufs-$(CONFIG_AUFS_HFSNOTIFY) += hfsnotify.o ++aufs-$(CONFIG_AUFS_EXPORT) += export.o ++aufs-$(CONFIG_AUFS_XATTR) += xattr.o ++aufs-$(CONFIG_FS_POSIX_ACL) += posix_acl.o ++aufs-$(CONFIG_AUFS_DIRREN) += dirren.o ++aufs-$(CONFIG_AUFS_FHSM) += fhsm.o ++aufs-$(CONFIG_AUFS_POLL) += poll.o ++aufs-$(CONFIG_AUFS_RDU) += rdu.o ++aufs-$(CONFIG_AUFS_BR_HFSPLUS) += hfsplus.o ++aufs-$(CONFIG_AUFS_DEBUG) += debug.o ++aufs-$(CONFIG_AUFS_MAGIC_SYSRQ) += sysrq.o +diff -Nurp linux-5.15.37/fs/aufs/module.c linux-5.15.37-aufs/fs/aufs/module.c +--- linux-5.15.37/fs/aufs/module.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/module.c 2022-04-08 20:22:30.614616573 +0300 +@@ -0,0 +1,259 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * module global variables and operations ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++/* shrinkable realloc */ ++void *au_krealloc(void *p, unsigned int new_sz, gfp_t gfp, int may_shrink) ++{ ++ size_t sz; ++ int diff; ++ ++ sz = 0; ++ diff = -1; ++ if (p) { ++#if 0 /* unused */ ++ if (!new_sz) { ++ au_kfree_rcu(p); ++ p = NULL; ++ goto out; ++ } ++#else ++ AuDebugOn(!new_sz); ++#endif ++ sz = ksize(p); ++ diff = au_kmidx_sub(sz, new_sz); ++ } ++ if (sz && !diff) ++ goto out; ++ ++ if (sz < new_sz) ++ /* expand or SLOB */ ++ p = krealloc(p, new_sz, gfp); ++ else if (new_sz < sz && may_shrink) { ++ /* shrink */ ++ void *q; ++ ++ q = kmalloc(new_sz, gfp); ++ if (q) { ++ if (p) { ++ memcpy(q, p, new_sz); ++ au_kfree_try_rcu(p); ++ } ++ p = q; ++ } else ++ p = NULL; ++ } ++ ++out: ++ return p; ++} ++ ++void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp, ++ int may_shrink) ++{ ++ p = au_krealloc(p, new_sz, gfp, may_shrink); ++ if (p && new_sz > nused) ++ memset(p + nused, 0, new_sz - nused); ++ return p; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * aufs caches ++ */ ++struct kmem_cache *au_cache[AuCache_Last]; ++ ++static void au_cache_fin(void) ++{ ++ int i; ++ ++ /* ++ * Make sure all delayed rcu free inodes are flushed before we ++ * destroy cache. ++ */ ++ rcu_barrier(); ++ ++ /* excluding AuCache_HNOTIFY */ ++ BUILD_BUG_ON(AuCache_HNOTIFY + 1 != AuCache_Last); ++ for (i = 0; i < AuCache_HNOTIFY; i++) { ++ kmem_cache_destroy(au_cache[i]); ++ au_cache[i] = NULL; ++ } ++} ++ ++static int __init au_cache_init(void) ++{ ++ au_cache[AuCache_DINFO] = AuCacheCtor(au_dinfo, au_di_init_once); ++ if (au_cache[AuCache_DINFO]) ++ /* SLAB_DESTROY_BY_RCU */ ++ au_cache[AuCache_ICNTNR] = AuCacheCtor(au_icntnr, ++ au_icntnr_init_once); ++ if (au_cache[AuCache_ICNTNR]) ++ au_cache[AuCache_FINFO] = AuCacheCtor(au_finfo, ++ au_fi_init_once); ++ if (au_cache[AuCache_FINFO]) ++ au_cache[AuCache_VDIR] = AuCache(au_vdir); ++ if (au_cache[AuCache_VDIR]) ++ au_cache[AuCache_DEHSTR] = AuCache(au_vdir_dehstr); ++ if (au_cache[AuCache_DEHSTR]) ++ return 0; ++ ++ au_cache_fin(); ++ return -ENOMEM; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_dir_roflags; ++ ++#ifdef CONFIG_AUFS_SBILIST ++/* ++ * iterate_supers_type() doesn't protect us from ++ * remounting (branch management) ++ */ ++struct hlist_bl_head au_sbilist; ++#endif ++ ++/* ++ * functions for module interface. ++ */ ++MODULE_LICENSE("GPL"); ++/* MODULE_LICENSE("GPL v2"); */ ++MODULE_AUTHOR("Junjiro R. Okajima "); ++MODULE_DESCRIPTION(AUFS_NAME ++ " -- Advanced multi layered unification filesystem"); ++MODULE_VERSION(AUFS_VERSION); ++ ++/* this module parameter has no meaning when SYSFS is disabled */ ++int sysaufs_brs = 1; ++MODULE_PARM_DESC(brs, "use /fs/aufs/si_*/brN"); ++module_param_named(brs, sysaufs_brs, int, 0444); ++ ++/* this module parameter has no meaning when USER_NS is disabled */ ++bool au_userns; ++MODULE_PARM_DESC(allow_userns, "allow unprivileged to mount under userns"); ++module_param_named(allow_userns, au_userns, bool, 0444); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static char au_esc_chars[0x20 + 3]; /* 0x01-0x20, backslash, del, and NULL */ ++ ++int au_seq_path(struct seq_file *seq, struct path *path) ++{ ++ int err; ++ ++ err = seq_path(seq, path, au_esc_chars); ++ if (err >= 0) ++ err = 0; ++ else ++ err = -ENOMEM; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int __init aufs_init(void) ++{ ++ int err, i; ++ char *p; ++ ++ p = au_esc_chars; ++ for (i = 1; i <= ' '; i++) ++ *p++ = i; ++ *p++ = '\\'; ++ *p++ = '\x7f'; ++ *p = 0; ++ ++ au_dir_roflags = au_file_roflags(O_DIRECTORY | O_LARGEFILE); ++ ++ memcpy(aufs_iop_nogetattr, aufs_iop, sizeof(aufs_iop)); ++ for (i = 0; i < AuIop_Last; i++) ++ aufs_iop_nogetattr[i].getattr = NULL; ++ ++ memset(au_cache, 0, sizeof(au_cache)); /* including hnotify */ ++ ++ au_sbilist_init(); ++ sysaufs_brs_init(); ++ au_debug_init(); ++ au_dy_init(); ++ err = sysaufs_init(); ++ if (unlikely(err)) ++ goto out; ++ err = dbgaufs_init(); ++ if (unlikely(err)) ++ goto out_sysaufs; ++ err = au_procfs_init(); ++ if (unlikely(err)) ++ goto out_dbgaufs; ++ err = au_wkq_init(); ++ if (unlikely(err)) ++ goto out_procfs; ++ err = au_loopback_init(); ++ if (unlikely(err)) ++ goto out_wkq; ++ err = au_hnotify_init(); ++ if (unlikely(err)) ++ goto out_loopback; ++ err = au_sysrq_init(); ++ if (unlikely(err)) ++ goto out_hin; ++ err = au_cache_init(); ++ if (unlikely(err)) ++ goto out_sysrq; ++ ++ aufs_fs_type.fs_flags |= au_userns ? FS_USERNS_MOUNT : 0; ++ err = register_filesystem(&aufs_fs_type); ++ if (unlikely(err)) ++ goto out_cache; ++ ++ /* since we define pr_fmt, call printk directly */ ++ printk(KERN_INFO AUFS_NAME " " AUFS_VERSION "\n"); ++ goto out; /* success */ ++ ++out_cache: ++ au_cache_fin(); ++out_sysrq: ++ au_sysrq_fin(); ++out_hin: ++ au_hnotify_fin(); ++out_loopback: ++ au_loopback_fin(); ++out_wkq: ++ au_wkq_fin(); ++out_procfs: ++ au_procfs_fin(); ++out_dbgaufs: ++ dbgaufs_fin(); ++out_sysaufs: ++ sysaufs_fin(); ++ au_dy_fin(); ++out: ++ return err; ++} ++ ++static void __exit aufs_exit(void) ++{ ++ unregister_filesystem(&aufs_fs_type); ++ au_cache_fin(); ++ au_sysrq_fin(); ++ au_hnotify_fin(); ++ au_loopback_fin(); ++ au_wkq_fin(); ++ au_procfs_fin(); ++ dbgaufs_fin(); ++ sysaufs_fin(); ++ au_dy_fin(); ++} ++ ++module_init(aufs_init); ++module_exit(aufs_exit); +diff -Nurp linux-5.15.37/fs/aufs/module.h linux-5.15.37-aufs/fs/aufs/module.h +--- linux-5.15.37/fs/aufs/module.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/module.h 2022-04-08 20:22:30.614616573 +0300 +@@ -0,0 +1,153 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * module initialization and module-global ++ */ ++ ++#ifndef __AUFS_MODULE_H__ ++#define __AUFS_MODULE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "debug.h" ++#include "dentry.h" ++#include "dir.h" ++#include "file.h" ++#include "inode.h" ++ ++struct path; ++struct seq_file; ++ ++/* module parameters */ ++extern int sysaufs_brs; ++extern bool au_userns; ++ ++/* ---------------------------------------------------------------------- */ ++ ++extern int au_dir_roflags; ++ ++void *au_krealloc(void *p, unsigned int new_sz, gfp_t gfp, int may_shrink); ++void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp, ++ int may_shrink); ++ ++/* ++ * Comparing the size of the object with sizeof(struct rcu_head) ++ * case 1: object is always larger ++ * --> au_kfree_rcu() or au_kfree_do_rcu() ++ * case 2: object is always smaller ++ * --> au_kfree_small() ++ * case 3: object can be any size ++ * --> au_kfree_try_rcu() ++ */ ++ ++static inline void au_kfree_do_rcu(const void *p) ++{ ++ struct { ++ struct rcu_head rcu; ++ } *a = (void *)p; ++ ++ kfree_rcu(a, rcu); ++} ++ ++#define au_kfree_rcu(_p) do { \ ++ typeof(_p) p = (_p); \ ++ BUILD_BUG_ON(sizeof(*p) < sizeof(struct rcu_head)); \ ++ if (p) \ ++ au_kfree_do_rcu(p); \ ++ } while (0) ++ ++#define au_kfree_do_sz_test(sz) (sz >= sizeof(struct rcu_head)) ++#define au_kfree_sz_test(p) (p && au_kfree_do_sz_test(ksize(p))) ++ ++static inline void au_kfree_try_rcu(const void *p) ++{ ++ if (!p) ++ return; ++ if (au_kfree_sz_test(p)) ++ au_kfree_do_rcu(p); ++ else ++ kfree(p); ++} ++ ++static inline void au_kfree_small(const void *p) ++{ ++ if (!p) ++ return; ++ AuDebugOn(au_kfree_sz_test(p)); ++ kfree(p); ++} ++ ++static inline int au_kmidx_sub(size_t sz, size_t new_sz) ++{ ++#ifndef CONFIG_SLOB ++ return __kmalloc_index(sz, false) - __kmalloc_index(new_sz, false); ++#else ++ return -1; /* SLOB is untested */ ++#endif ++} ++ ++int au_seq_path(struct seq_file *seq, struct path *path); ++ ++#ifdef CONFIG_PROC_FS ++/* procfs.c */ ++int __init au_procfs_init(void); ++void au_procfs_fin(void); ++#else ++AuStubInt0(au_procfs_init, void); ++AuStubVoid(au_procfs_fin, void); ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* kmem cache */ ++enum { ++ AuCache_DINFO, ++ AuCache_ICNTNR, ++ AuCache_FINFO, ++ AuCache_VDIR, ++ AuCache_DEHSTR, ++ AuCache_HNOTIFY, /* must be last */ ++ AuCache_Last ++}; ++ ++extern struct kmem_cache *au_cache[AuCache_Last]; ++ ++#define AuCacheFlags (SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD) ++#define AuCache(type) KMEM_CACHE(type, AuCacheFlags) ++#define AuCacheCtor(type, ctor) \ ++ kmem_cache_create(#type, sizeof(struct type), \ ++ __alignof__(struct type), AuCacheFlags, ctor) ++ ++#define AuCacheFuncs(name, index) \ ++ static inline struct au_##name *au_cache_alloc_##name(void) \ ++ { return kmem_cache_alloc(au_cache[AuCache_##index], GFP_NOFS); } \ ++ static inline void au_cache_free_##name##_norcu(struct au_##name *p) \ ++ { kmem_cache_free(au_cache[AuCache_##index], p); } \ ++ \ ++ static inline void au_cache_free_##name##_rcu_cb(struct rcu_head *rcu) \ ++ { void *p = rcu; \ ++ p -= offsetof(struct au_##name, rcu); \ ++ kmem_cache_free(au_cache[AuCache_##index], p); } \ ++ static inline void au_cache_free_##name##_rcu(struct au_##name *p) \ ++ { BUILD_BUG_ON(sizeof(struct au_##name) < sizeof(struct rcu_head)); \ ++ call_rcu(&p->rcu, au_cache_free_##name##_rcu_cb); } \ ++ \ ++ static inline void au_cache_free_##name(struct au_##name *p) \ ++ { /* au_cache_free_##name##_norcu(p); */ \ ++ au_cache_free_##name##_rcu(p); } ++ ++AuCacheFuncs(dinfo, DINFO); ++AuCacheFuncs(icntnr, ICNTNR); ++AuCacheFuncs(finfo, FINFO); ++AuCacheFuncs(vdir, VDIR); ++AuCacheFuncs(vdir_dehstr, DEHSTR); ++#ifdef CONFIG_AUFS_HNOTIFY ++AuCacheFuncs(hnotify, HNOTIFY); ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_MODULE_H__ */ +diff -Nurp linux-5.15.37/fs/aufs/mvdown.c linux-5.15.37-aufs/fs/aufs/mvdown.c +--- linux-5.15.37/fs/aufs/mvdown.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/mvdown.c 2022-04-08 20:22:30.614616573 +0300 +@@ -0,0 +1,693 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2011-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * move-down, opposite of copy-up ++ */ ++ ++#include "aufs.h" ++ ++struct au_mvd_args { ++ struct { ++ struct super_block *h_sb; ++ struct dentry *h_parent; ++ struct au_hinode *hdir; ++ struct inode *h_dir, *h_inode; ++ struct au_pin pin; ++ } info[AUFS_MVDOWN_NARRAY]; ++ ++ struct aufs_mvdown mvdown; ++ struct dentry *dentry, *parent; ++ struct inode *inode, *dir; ++ struct super_block *sb; ++ aufs_bindex_t bopq, bwh, bfound; ++ unsigned char rename_lock; ++}; ++ ++#define mvd_errno mvdown.au_errno ++#define mvd_bsrc mvdown.stbr[AUFS_MVDOWN_UPPER].bindex ++#define mvd_src_brid mvdown.stbr[AUFS_MVDOWN_UPPER].brid ++#define mvd_bdst mvdown.stbr[AUFS_MVDOWN_LOWER].bindex ++#define mvd_dst_brid mvdown.stbr[AUFS_MVDOWN_LOWER].brid ++ ++#define mvd_h_src_sb info[AUFS_MVDOWN_UPPER].h_sb ++#define mvd_h_src_parent info[AUFS_MVDOWN_UPPER].h_parent ++#define mvd_hdir_src info[AUFS_MVDOWN_UPPER].hdir ++#define mvd_h_src_dir info[AUFS_MVDOWN_UPPER].h_dir ++#define mvd_h_src_inode info[AUFS_MVDOWN_UPPER].h_inode ++#define mvd_pin_src info[AUFS_MVDOWN_UPPER].pin ++ ++#define mvd_h_dst_sb info[AUFS_MVDOWN_LOWER].h_sb ++#define mvd_h_dst_parent info[AUFS_MVDOWN_LOWER].h_parent ++#define mvd_hdir_dst info[AUFS_MVDOWN_LOWER].hdir ++#define mvd_h_dst_dir info[AUFS_MVDOWN_LOWER].h_dir ++#define mvd_h_dst_inode info[AUFS_MVDOWN_LOWER].h_inode ++#define mvd_pin_dst info[AUFS_MVDOWN_LOWER].pin ++ ++#define AU_MVD_PR(flag, ...) do { \ ++ if (flag) \ ++ pr_err(__VA_ARGS__); \ ++ } while (0) ++ ++static int find_lower_writable(struct au_mvd_args *a) ++{ ++ struct super_block *sb; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ sb = a->sb; ++ bindex = a->mvd_bsrc; ++ bbot = au_sbbot(sb); ++ if (a->mvdown.flags & AUFS_MVDOWN_FHSM_LOWER) ++ for (bindex++; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm) ++ && !sb_rdonly(au_br_sb(br))) ++ return bindex; ++ } ++ else if (!(a->mvdown.flags & AUFS_MVDOWN_ROLOWER)) ++ for (bindex++; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!au_br_rdonly(br)) ++ return bindex; ++ } ++ else ++ for (bindex++; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!sb_rdonly(au_br_sb(br))) { ++ if (au_br_rdonly(br)) ++ a->mvdown.flags ++ |= AUFS_MVDOWN_ROLOWER_R; ++ return bindex; ++ } ++ } ++ ++ return -1; ++} ++ ++/* make the parent dir on bdst */ ++static int au_do_mkdir(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ ++ err = 0; ++ a->mvd_hdir_src = au_hi(a->dir, a->mvd_bsrc); ++ a->mvd_hdir_dst = au_hi(a->dir, a->mvd_bdst); ++ a->mvd_h_src_parent = au_h_dptr(a->parent, a->mvd_bsrc); ++ a->mvd_h_dst_parent = NULL; ++ if (au_dbbot(a->parent) >= a->mvd_bdst) ++ a->mvd_h_dst_parent = au_h_dptr(a->parent, a->mvd_bdst); ++ if (!a->mvd_h_dst_parent) { ++ err = au_cpdown_dirs(a->dentry, a->mvd_bdst); ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "cpdown_dirs failed\n"); ++ goto out; ++ } ++ a->mvd_h_dst_parent = au_h_dptr(a->parent, a->mvd_bdst); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* lock them all */ ++static int au_do_lock(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct dentry *h_trap; ++ ++ a->mvd_h_src_sb = au_sbr_sb(a->sb, a->mvd_bsrc); ++ a->mvd_h_dst_sb = au_sbr_sb(a->sb, a->mvd_bdst); ++ err = au_pin(&a->mvd_pin_dst, a->dentry, a->mvd_bdst, ++ au_opt_udba(a->sb), ++ AuPin_MNT_WRITE | AuPin_DI_LOCKED); ++ AuTraceErr(err); ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "pin_dst failed\n"); ++ goto out; ++ } ++ ++ if (a->mvd_h_src_sb != a->mvd_h_dst_sb) { ++ a->rename_lock = 0; ++ au_pin_init(&a->mvd_pin_src, a->dentry, a->mvd_bsrc, ++ AuLsc_DI_PARENT, AuLsc_I_PARENT3, ++ au_opt_udba(a->sb), ++ AuPin_MNT_WRITE | AuPin_DI_LOCKED); ++ err = au_do_pin(&a->mvd_pin_src); ++ AuTraceErr(err); ++ a->mvd_h_src_dir = d_inode(a->mvd_h_src_parent); ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "pin_src failed\n"); ++ goto out_dst; ++ } ++ goto out; /* success */ ++ } ++ ++ a->rename_lock = 1; ++ au_pin_hdir_unlock(&a->mvd_pin_dst); ++ err = au_pin(&a->mvd_pin_src, a->dentry, a->mvd_bsrc, ++ au_opt_udba(a->sb), ++ AuPin_MNT_WRITE | AuPin_DI_LOCKED); ++ AuTraceErr(err); ++ a->mvd_h_src_dir = d_inode(a->mvd_h_src_parent); ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "pin_src failed\n"); ++ au_pin_hdir_lock(&a->mvd_pin_dst); ++ goto out_dst; ++ } ++ au_pin_hdir_unlock(&a->mvd_pin_src); ++ h_trap = vfsub_lock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, ++ a->mvd_h_dst_parent, a->mvd_hdir_dst); ++ if (h_trap) { ++ err = (h_trap != a->mvd_h_src_parent); ++ if (err) ++ err = (h_trap != a->mvd_h_dst_parent); ++ } ++ BUG_ON(err); /* it should never happen */ ++ if (unlikely(a->mvd_h_src_dir != au_pinned_h_dir(&a->mvd_pin_src))) { ++ err = -EBUSY; ++ AuTraceErr(err); ++ vfsub_unlock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, ++ a->mvd_h_dst_parent, a->mvd_hdir_dst); ++ au_pin_hdir_lock(&a->mvd_pin_src); ++ au_unpin(&a->mvd_pin_src); ++ au_pin_hdir_lock(&a->mvd_pin_dst); ++ goto out_dst; ++ } ++ goto out; /* success */ ++ ++out_dst: ++ au_unpin(&a->mvd_pin_dst); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static void au_do_unlock(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ if (!a->rename_lock) ++ au_unpin(&a->mvd_pin_src); ++ else { ++ vfsub_unlock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, ++ a->mvd_h_dst_parent, a->mvd_hdir_dst); ++ au_pin_hdir_lock(&a->mvd_pin_src); ++ au_unpin(&a->mvd_pin_src); ++ au_pin_hdir_lock(&a->mvd_pin_dst); ++ } ++ au_unpin(&a->mvd_pin_dst); ++} ++ ++/* copy-down the file */ ++static int au_do_cpdown(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct au_cp_generic cpg = { ++ .dentry = a->dentry, ++ .bdst = a->mvd_bdst, ++ .bsrc = a->mvd_bsrc, ++ .len = -1, ++ .pin = &a->mvd_pin_dst, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ ++ AuDbg("b%d, b%d\n", cpg.bsrc, cpg.bdst); ++ if (a->mvdown.flags & AUFS_MVDOWN_OWLOWER) ++ au_fset_cpup(cpg.flags, OVERWRITE); ++ if (a->mvdown.flags & AUFS_MVDOWN_ROLOWER) ++ au_fset_cpup(cpg.flags, RWDST); ++ err = au_sio_cpdown_simple(&cpg); ++ if (unlikely(err)) ++ AU_MVD_PR(dmsg, "cpdown failed\n"); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * unlink the whiteout on bdst if exist which may be created by UDBA while we ++ * were sleeping ++ */ ++static int au_do_unlink_wh(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct path h_path; ++ struct au_branch *br; ++ struct inode *delegated; ++ ++ br = au_sbr(a->sb, a->mvd_bdst); ++ h_path.dentry = au_wh_lkup(a->mvd_h_dst_parent, &a->dentry->d_name, br); ++ err = PTR_ERR(h_path.dentry); ++ if (IS_ERR(h_path.dentry)) { ++ AU_MVD_PR(dmsg, "wh_lkup failed\n"); ++ goto out; ++ } ++ ++ err = 0; ++ if (d_is_positive(h_path.dentry)) { ++ h_path.mnt = au_br_mnt(br); ++ delegated = NULL; ++ err = vfsub_unlink(d_inode(a->mvd_h_dst_parent), &h_path, ++ &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ if (unlikely(err)) ++ AU_MVD_PR(dmsg, "wh_unlink failed\n"); ++ } ++ dput(h_path.dentry); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * unlink the topmost h_dentry ++ */ ++static int au_do_unlink(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct path h_path; ++ struct inode *delegated; ++ ++ h_path.mnt = au_sbr_mnt(a->sb, a->mvd_bsrc); ++ h_path.dentry = au_h_dptr(a->dentry, a->mvd_bsrc); ++ delegated = NULL; ++ err = vfsub_unlink(a->mvd_h_src_dir, &h_path, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ if (unlikely(err)) ++ AU_MVD_PR(dmsg, "unlink failed\n"); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* Since mvdown succeeded, we ignore an error of this function */ ++static void au_do_stfs(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct au_branch *br; ++ ++ a->mvdown.flags |= AUFS_MVDOWN_STFS_FAILED; ++ br = au_sbr(a->sb, a->mvd_bsrc); ++ err = au_br_stfs(br, &a->mvdown.stbr[AUFS_MVDOWN_UPPER].stfs); ++ if (!err) { ++ br = au_sbr(a->sb, a->mvd_bdst); ++ a->mvdown.stbr[AUFS_MVDOWN_LOWER].brid = br->br_id; ++ err = au_br_stfs(br, &a->mvdown.stbr[AUFS_MVDOWN_LOWER].stfs); ++ } ++ if (!err) ++ a->mvdown.flags &= ~AUFS_MVDOWN_STFS_FAILED; ++ else ++ AU_MVD_PR(dmsg, "statfs failed (%d), ignored\n", err); ++} ++ ++/* ++ * copy-down the file and unlink the bsrc file. ++ * - unlink the bdst whout if exist ++ * - copy-down the file (with whtmp name and rename) ++ * - unlink the bsrc file ++ */ ++static int au_do_mvdown(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ ++ err = au_do_mkdir(dmsg, a); ++ if (!err) ++ err = au_do_lock(dmsg, a); ++ if (unlikely(err)) ++ goto out; ++ ++ /* ++ * do not revert the activities we made on bdst since they should be ++ * harmless in aufs. ++ */ ++ ++ err = au_do_cpdown(dmsg, a); ++ if (!err) ++ err = au_do_unlink_wh(dmsg, a); ++ if (!err && !(a->mvdown.flags & AUFS_MVDOWN_KUPPER)) ++ err = au_do_unlink(dmsg, a); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ AuDbg("%pd2, 0x%x, %d --> %d\n", ++ a->dentry, a->mvdown.flags, a->mvd_bsrc, a->mvd_bdst); ++ if (find_lower_writable(a) < 0) ++ a->mvdown.flags |= AUFS_MVDOWN_BOTTOM; ++ ++ if (a->mvdown.flags & AUFS_MVDOWN_STFS) ++ au_do_stfs(dmsg, a); ++ ++ /* maintain internal array */ ++ if (!(a->mvdown.flags & AUFS_MVDOWN_KUPPER)) { ++ au_set_h_dptr(a->dentry, a->mvd_bsrc, NULL); ++ au_set_dbtop(a->dentry, a->mvd_bdst); ++ au_set_h_iptr(a->inode, a->mvd_bsrc, NULL, /*flags*/0); ++ au_set_ibtop(a->inode, a->mvd_bdst); ++ } else { ++ /* hide the lower */ ++ au_set_h_dptr(a->dentry, a->mvd_bdst, NULL); ++ au_set_dbbot(a->dentry, a->mvd_bsrc); ++ au_set_h_iptr(a->inode, a->mvd_bdst, NULL, /*flags*/0); ++ au_set_ibbot(a->inode, a->mvd_bsrc); ++ } ++ if (au_dbbot(a->dentry) < a->mvd_bdst) ++ au_set_dbbot(a->dentry, a->mvd_bdst); ++ if (au_ibbot(a->inode) < a->mvd_bdst) ++ au_set_ibbot(a->inode, a->mvd_bdst); ++ ++out_unlock: ++ au_do_unlock(dmsg, a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* make sure the file is idle */ ++static int au_mvd_args_busy(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err, plinked; ++ ++ err = 0; ++ plinked = !!au_opt_test(au_mntflags(a->sb), PLINK); ++ if (au_dbtop(a->dentry) == a->mvd_bsrc ++ && au_dcount(a->dentry) == 1 ++ && atomic_read(&a->inode->i_count) == 1 ++ /* && a->mvd_h_src_inode->i_nlink == 1 */ ++ && (!plinked || !au_plink_test(a->inode)) ++ && a->inode->i_nlink == 1) ++ goto out; ++ ++ err = -EBUSY; ++ AU_MVD_PR(dmsg, ++ "b%d, d{b%d, c%d?}, i{c%d?, l%u}, hi{l%u}, p{%d, %d}\n", ++ a->mvd_bsrc, au_dbtop(a->dentry), au_dcount(a->dentry), ++ atomic_read(&a->inode->i_count), a->inode->i_nlink, ++ a->mvd_h_src_inode->i_nlink, ++ plinked, plinked ? au_plink_test(a->inode) : 0); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* make sure the parent dir is fine */ ++static int au_mvd_args_parent(const unsigned char dmsg, ++ struct au_mvd_args *a) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ ++ err = 0; ++ if (unlikely(au_alive_dir(a->parent))) { ++ err = -ENOENT; ++ AU_MVD_PR(dmsg, "parent dir is dead\n"); ++ goto out; ++ } ++ ++ a->bopq = au_dbdiropq(a->parent); ++ bindex = au_wbr_nonopq(a->dentry, a->mvd_bdst); ++ AuDbg("b%d\n", bindex); ++ if (unlikely((bindex >= 0 && bindex < a->mvd_bdst) ++ || (a->bopq != -1 && a->bopq < a->mvd_bdst))) { ++ err = -EINVAL; ++ a->mvd_errno = EAU_MVDOWN_OPAQUE; ++ AU_MVD_PR(dmsg, "ancestor is opaque b%d, b%d\n", ++ a->bopq, a->mvd_bdst); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_mvd_args_intermediate(const unsigned char dmsg, ++ struct au_mvd_args *a) ++{ ++ int err; ++ struct au_dinfo *dinfo, *tmp; ++ ++ /* lookup the next lower positive entry */ ++ err = -ENOMEM; ++ tmp = au_di_alloc(a->sb, AuLsc_DI_TMP); ++ if (unlikely(!tmp)) ++ goto out; ++ ++ a->bfound = -1; ++ a->bwh = -1; ++ dinfo = au_di(a->dentry); ++ au_di_cp(tmp, dinfo); ++ au_di_swap(tmp, dinfo); ++ ++ /* returns the number of positive dentries */ ++ err = au_lkup_dentry(a->dentry, a->mvd_bsrc + 1, ++ /* AuLkup_IGNORE_PERM */ 0); ++ if (!err) ++ a->bwh = au_dbwh(a->dentry); ++ else if (err > 0) ++ a->bfound = au_dbtop(a->dentry); ++ ++ au_di_swap(tmp, dinfo); ++ au_rw_write_unlock(&tmp->di_rwsem); ++ au_di_free(tmp); ++ if (unlikely(err < 0)) ++ AU_MVD_PR(dmsg, "failed look-up lower\n"); ++ ++ /* ++ * here, we have these cases. ++ * bfound == -1 ++ * no positive dentry under bsrc. there are more sub-cases. ++ * bwh < 0 ++ * there no whiteout, we can safely move-down. ++ * bwh <= bsrc ++ * impossible ++ * bsrc < bwh && bwh < bdst ++ * there is a whiteout on RO branch. cannot proceed. ++ * bwh == bdst ++ * there is a whiteout on the RW target branch. it should ++ * be removed. ++ * bdst < bwh ++ * there is a whiteout somewhere unrelated branch. ++ * -1 < bfound && bfound <= bsrc ++ * impossible. ++ * bfound < bdst ++ * found, but it is on RO branch between bsrc and bdst. cannot ++ * proceed. ++ * bfound == bdst ++ * found, replace it if AUFS_MVDOWN_FORCE is set. otherwise return ++ * error. ++ * bdst < bfound ++ * found, after we create the file on bdst, it will be hidden. ++ */ ++ ++ AuDebugOn(a->bfound == -1 ++ && a->bwh != -1 ++ && a->bwh <= a->mvd_bsrc); ++ AuDebugOn(-1 < a->bfound ++ && a->bfound <= a->mvd_bsrc); ++ ++ err = -EINVAL; ++ if (a->bfound == -1 ++ && a->mvd_bsrc < a->bwh ++ && a->bwh != -1 ++ && a->bwh < a->mvd_bdst) { ++ a->mvd_errno = EAU_MVDOWN_WHITEOUT; ++ AU_MVD_PR(dmsg, "bsrc %d, bdst %d, bfound %d, bwh %d\n", ++ a->mvd_bsrc, a->mvd_bdst, a->bfound, a->bwh); ++ goto out; ++ } else if (a->bfound != -1 && a->bfound < a->mvd_bdst) { ++ a->mvd_errno = EAU_MVDOWN_UPPER; ++ AU_MVD_PR(dmsg, "bdst %d, bfound %d\n", ++ a->mvd_bdst, a->bfound); ++ goto out; ++ } ++ ++ err = 0; /* success */ ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_mvd_args_exist(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ ++ err = 0; ++ if (!(a->mvdown.flags & AUFS_MVDOWN_OWLOWER) ++ && a->bfound == a->mvd_bdst) ++ err = -EEXIST; ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_mvd_args(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct au_branch *br; ++ ++ err = -EISDIR; ++ if (unlikely(S_ISDIR(a->inode->i_mode))) ++ goto out; ++ ++ err = -EINVAL; ++ if (!(a->mvdown.flags & AUFS_MVDOWN_BRID_UPPER)) ++ a->mvd_bsrc = au_ibtop(a->inode); ++ else { ++ a->mvd_bsrc = au_br_index(a->sb, a->mvd_src_brid); ++ if (unlikely(a->mvd_bsrc < 0 ++ || (a->mvd_bsrc < au_dbtop(a->dentry) ++ || au_dbbot(a->dentry) < a->mvd_bsrc ++ || !au_h_dptr(a->dentry, a->mvd_bsrc)) ++ || (a->mvd_bsrc < au_ibtop(a->inode) ++ || au_ibbot(a->inode) < a->mvd_bsrc ++ || !au_h_iptr(a->inode, a->mvd_bsrc)))) { ++ a->mvd_errno = EAU_MVDOWN_NOUPPER; ++ AU_MVD_PR(dmsg, "no upper\n"); ++ goto out; ++ } ++ } ++ if (unlikely(a->mvd_bsrc == au_sbbot(a->sb))) { ++ a->mvd_errno = EAU_MVDOWN_BOTTOM; ++ AU_MVD_PR(dmsg, "on the bottom\n"); ++ goto out; ++ } ++ a->mvd_h_src_inode = au_h_iptr(a->inode, a->mvd_bsrc); ++ br = au_sbr(a->sb, a->mvd_bsrc); ++ err = au_br_rdonly(br); ++ if (!(a->mvdown.flags & AUFS_MVDOWN_ROUPPER)) { ++ if (unlikely(err)) ++ goto out; ++ } else if (!(vfsub_native_ro(a->mvd_h_src_inode) ++ || IS_APPEND(a->mvd_h_src_inode))) { ++ if (err) ++ a->mvdown.flags |= AUFS_MVDOWN_ROUPPER_R; ++ /* go on */ ++ } else ++ goto out; ++ ++ err = -EINVAL; ++ if (!(a->mvdown.flags & AUFS_MVDOWN_BRID_LOWER)) { ++ a->mvd_bdst = find_lower_writable(a); ++ if (unlikely(a->mvd_bdst < 0)) { ++ a->mvd_errno = EAU_MVDOWN_BOTTOM; ++ AU_MVD_PR(dmsg, "no writable lower branch\n"); ++ goto out; ++ } ++ } else { ++ a->mvd_bdst = au_br_index(a->sb, a->mvd_dst_brid); ++ if (unlikely(a->mvd_bdst < 0 ++ || au_sbbot(a->sb) < a->mvd_bdst)) { ++ a->mvd_errno = EAU_MVDOWN_NOLOWERBR; ++ AU_MVD_PR(dmsg, "no lower brid\n"); ++ goto out; ++ } ++ } ++ ++ err = au_mvd_args_busy(dmsg, a); ++ if (!err) ++ err = au_mvd_args_parent(dmsg, a); ++ if (!err) ++ err = au_mvd_args_intermediate(dmsg, a); ++ if (!err) ++ err = au_mvd_args_exist(dmsg, a); ++ if (!err) ++ AuDbg("b%d, b%d\n", a->mvd_bsrc, a->mvd_bdst); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *uarg) ++{ ++ int err, e; ++ unsigned char dmsg; ++ struct au_mvd_args *args; ++ struct inode *inode; ++ ++ inode = d_inode(dentry); ++ err = -EPERM; ++ if (unlikely(!capable(CAP_SYS_ADMIN))) ++ goto out; ++ ++ err = -ENOMEM; ++ args = kmalloc(sizeof(*args), GFP_NOFS); ++ if (unlikely(!args)) ++ goto out; ++ ++ err = copy_from_user(&args->mvdown, uarg, sizeof(args->mvdown)); ++ if (!err) ++ /* VERIFY_WRITE */ ++ err = !access_ok(uarg, sizeof(*uarg)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out_free; ++ } ++ AuDbg("flags 0x%x\n", args->mvdown.flags); ++ args->mvdown.flags &= ~(AUFS_MVDOWN_ROLOWER_R | AUFS_MVDOWN_ROUPPER_R); ++ args->mvdown.au_errno = 0; ++ args->dentry = dentry; ++ args->inode = inode; ++ args->sb = dentry->d_sb; ++ ++ err = -ENOENT; ++ dmsg = !!(args->mvdown.flags & AUFS_MVDOWN_DMSG); ++ args->parent = dget_parent(dentry); ++ args->dir = d_inode(args->parent); ++ inode_lock_nested(args->dir, I_MUTEX_PARENT); ++ dput(args->parent); ++ if (unlikely(args->parent != dentry->d_parent)) { ++ AU_MVD_PR(dmsg, "parent dir is moved\n"); ++ goto out_dir; ++ } ++ ++ inode_lock_nested(inode, I_MUTEX_CHILD); ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_NOPLMW); ++ if (unlikely(err)) ++ goto out_inode; ++ ++ di_write_lock_parent(args->parent); ++ err = au_mvd_args(dmsg, args); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ err = au_do_mvdown(dmsg, args); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ au_cpup_attr_timesizes(args->dir); ++ au_cpup_attr_timesizes(inode); ++ if (!(args->mvdown.flags & AUFS_MVDOWN_KUPPER)) ++ au_cpup_igen(inode, au_h_iptr(inode, args->mvd_bdst)); ++ /* au_digen_dec(dentry); */ ++ ++out_parent: ++ di_write_unlock(args->parent); ++ aufs_read_unlock(dentry, AuLock_DW); ++out_inode: ++ inode_unlock(inode); ++out_dir: ++ inode_unlock(args->dir); ++out_free: ++ e = copy_to_user(uarg, &args->mvdown, sizeof(args->mvdown)); ++ if (unlikely(e)) ++ err = -EFAULT; ++ au_kfree_rcu(args); ++out: ++ AuTraceErr(err); ++ return err; ++} +diff -Nurp linux-5.15.37/fs/aufs/opts.c linux-5.15.37-aufs/fs/aufs/opts.c +--- linux-5.15.37/fs/aufs/opts.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/opts.c 2022-04-08 20:22:30.614616573 +0300 +@@ -0,0 +1,1019 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * mount options/flags ++ */ ++ ++#include /* a distribution requires */ ++#include ++#include "aufs.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++static const char *au_parser_pattern(int val, match_table_t tbl) ++{ ++ struct match_token *p; ++ ++ p = tbl; ++ while (p->pattern) { ++ if (p->token == val) ++ return p->pattern; ++ p++; ++ } ++ BUG(); ++ return "??"; ++} ++ ++static const char *au_optstr(int *val, match_table_t tbl) ++{ ++ struct match_token *p; ++ int v; ++ ++ v = *val; ++ if (!v) ++ goto out; ++ p = tbl; ++ while (p->pattern) { ++ if (p->token ++ && (v & p->token) == p->token) { ++ *val &= ~p->token; ++ return p->pattern; ++ } ++ p++; ++ } ++ ++out: ++ return NULL; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static match_table_t brperm = { ++ {AuBrPerm_RO, AUFS_BRPERM_RO}, ++ {AuBrPerm_RR, AUFS_BRPERM_RR}, ++ {AuBrPerm_RW, AUFS_BRPERM_RW}, ++ {0, NULL} ++}; ++ ++static match_table_t brattr = { ++ /* general */ ++ {AuBrAttr_COO_REG, AUFS_BRATTR_COO_REG}, ++ {AuBrAttr_COO_ALL, AUFS_BRATTR_COO_ALL}, ++ /* 'unpin' attrib is meaningless since linux-3.18-rc1 */ ++ {AuBrAttr_UNPIN, AUFS_BRATTR_UNPIN}, ++#ifdef CONFIG_AUFS_FHSM ++ {AuBrAttr_FHSM, AUFS_BRATTR_FHSM}, ++#endif ++#ifdef CONFIG_AUFS_XATTR ++ {AuBrAttr_ICEX, AUFS_BRATTR_ICEX}, ++ {AuBrAttr_ICEX_SEC, AUFS_BRATTR_ICEX_SEC}, ++ {AuBrAttr_ICEX_SYS, AUFS_BRATTR_ICEX_SYS}, ++ {AuBrAttr_ICEX_TR, AUFS_BRATTR_ICEX_TR}, ++ {AuBrAttr_ICEX_USR, AUFS_BRATTR_ICEX_USR}, ++ {AuBrAttr_ICEX_OTH, AUFS_BRATTR_ICEX_OTH}, ++#endif ++ ++ /* ro/rr branch */ ++ {AuBrRAttr_WH, AUFS_BRRATTR_WH}, ++ ++ /* rw branch */ ++ {AuBrWAttr_MOO, AUFS_BRWATTR_MOO}, ++ {AuBrWAttr_NoLinkWH, AUFS_BRWATTR_NLWH}, ++ ++ {0, NULL} ++}; ++ ++static int br_attr_val(char *str, match_table_t table, substring_t args[]) ++{ ++ int attr, v; ++ char *p; ++ ++ attr = 0; ++ do { ++ p = strchr(str, '+'); ++ if (p) ++ *p = 0; ++ v = match_token(str, table, args); ++ if (v) { ++ if (v & AuBrAttr_CMOO_Mask) ++ attr &= ~AuBrAttr_CMOO_Mask; ++ attr |= v; ++ } else { ++ if (p) ++ *p = '+'; ++ pr_warn("ignored branch attribute %s\n", str); ++ break; ++ } ++ if (p) ++ str = p + 1; ++ } while (p); ++ ++ return attr; ++} ++ ++static int au_do_optstr_br_attr(au_br_perm_str_t *str, int perm) ++{ ++ int sz; ++ const char *p; ++ char *q; ++ ++ q = str->a; ++ *q = 0; ++ p = au_optstr(&perm, brattr); ++ if (p) { ++ sz = strlen(p); ++ memcpy(q, p, sz + 1); ++ q += sz; ++ } else ++ goto out; ++ ++ do { ++ p = au_optstr(&perm, brattr); ++ if (p) { ++ *q++ = '+'; ++ sz = strlen(p); ++ memcpy(q, p, sz + 1); ++ q += sz; ++ } ++ } while (p); ++ ++out: ++ return q - str->a; ++} ++ ++int au_br_perm_val(char *perm) ++{ ++ int val, bad, sz; ++ char *p; ++ substring_t args[MAX_OPT_ARGS]; ++ au_br_perm_str_t attr; ++ ++ p = strchr(perm, '+'); ++ if (p) ++ *p = 0; ++ val = match_token(perm, brperm, args); ++ if (!val) { ++ if (p) ++ *p = '+'; ++ pr_warn("ignored branch permission %s\n", perm); ++ val = AuBrPerm_RO; ++ goto out; ++ } ++ if (!p) ++ goto out; ++ ++ val |= br_attr_val(p + 1, brattr, args); ++ ++ bad = 0; ++ switch (val & AuBrPerm_Mask) { ++ case AuBrPerm_RO: ++ case AuBrPerm_RR: ++ bad = val & AuBrWAttr_Mask; ++ val &= ~AuBrWAttr_Mask; ++ break; ++ case AuBrPerm_RW: ++ bad = val & AuBrRAttr_Mask; ++ val &= ~AuBrRAttr_Mask; ++ break; ++ } ++ ++ /* ++ * 'unpin' attrib becomes meaningless since linux-3.18-rc1, but aufs ++ * does not treat it as an error, just warning. ++ * this is a tiny guard for the user operation. ++ */ ++ if (val & AuBrAttr_UNPIN) { ++ bad |= AuBrAttr_UNPIN; ++ val &= ~AuBrAttr_UNPIN; ++ } ++ ++ if (unlikely(bad)) { ++ sz = au_do_optstr_br_attr(&attr, bad); ++ AuDebugOn(!sz); ++ pr_warn("ignored branch attribute %s\n", attr.a); ++ } ++ ++out: ++ return val; ++} ++ ++void au_optstr_br_perm(au_br_perm_str_t *str, int perm) ++{ ++ au_br_perm_str_t attr; ++ const char *p; ++ char *q; ++ int sz; ++ ++ q = str->a; ++ p = au_optstr(&perm, brperm); ++ AuDebugOn(!p || !*p); ++ sz = strlen(p); ++ memcpy(q, p, sz + 1); ++ q += sz; ++ ++ sz = au_do_optstr_br_attr(&attr, perm); ++ if (sz) { ++ *q++ = '+'; ++ memcpy(q, attr.a, sz + 1); ++ } ++ ++ AuDebugOn(strlen(str->a) >= sizeof(str->a)); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static match_table_t udbalevel = { ++ {AuOpt_UDBA_REVAL, "reval"}, ++ {AuOpt_UDBA_NONE, "none"}, ++#ifdef CONFIG_AUFS_HNOTIFY ++ {AuOpt_UDBA_HNOTIFY, "notify"}, /* abstraction */ ++#ifdef CONFIG_AUFS_HFSNOTIFY ++ {AuOpt_UDBA_HNOTIFY, "fsnotify"}, ++#endif ++#endif ++ {-1, NULL} ++}; ++ ++int au_udba_val(char *str) ++{ ++ substring_t args[MAX_OPT_ARGS]; ++ ++ return match_token(str, udbalevel, args); ++} ++ ++const char *au_optstr_udba(int udba) ++{ ++ return au_parser_pattern(udba, udbalevel); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static match_table_t au_wbr_create_policy = { ++ {AuWbrCreate_TDP, "tdp"}, ++ {AuWbrCreate_TDP, "top-down-parent"}, ++ {AuWbrCreate_RR, "rr"}, ++ {AuWbrCreate_RR, "round-robin"}, ++ {AuWbrCreate_MFS, "mfs"}, ++ {AuWbrCreate_MFS, "most-free-space"}, ++ {AuWbrCreate_MFSV, "mfs:%d"}, ++ {AuWbrCreate_MFSV, "most-free-space:%d"}, ++ ++ /* top-down regardless the parent, and then mfs */ ++ {AuWbrCreate_TDMFS, "tdmfs:%d"}, ++ {AuWbrCreate_TDMFSV, "tdmfs:%d:%d"}, ++ ++ {AuWbrCreate_MFSRR, "mfsrr:%d"}, ++ {AuWbrCreate_MFSRRV, "mfsrr:%d:%d"}, ++ {AuWbrCreate_PMFS, "pmfs"}, ++ {AuWbrCreate_PMFSV, "pmfs:%d"}, ++ {AuWbrCreate_PMFSRR, "pmfsrr:%d"}, ++ {AuWbrCreate_PMFSRRV, "pmfsrr:%d:%d"}, ++ ++ {-1, NULL} ++}; ++ ++static int au_wbr_mfs_wmark(substring_t *arg, char *str, ++ struct au_opt_wbr_create *create) ++{ ++ int err; ++ unsigned long long ull; ++ ++ err = 0; ++ if (!match_u64(arg, &ull)) ++ create->mfsrr_watermark = ull; ++ else { ++ pr_err("bad integer in %s\n", str); ++ err = -EINVAL; ++ } ++ ++ return err; ++} ++ ++static int au_wbr_mfs_sec(substring_t *arg, char *str, ++ struct au_opt_wbr_create *create) ++{ ++ int n, err; ++ ++ err = 0; ++ if (!match_int(arg, &n) && 0 <= n && n <= AUFS_MFS_MAX_SEC) ++ create->mfs_second = n; ++ else { ++ pr_err("bad integer in %s\n", str); ++ err = -EINVAL; ++ } ++ ++ return err; ++} ++ ++int au_wbr_create_val(char *str, struct au_opt_wbr_create *create) ++{ ++ int err, e; ++ substring_t args[MAX_OPT_ARGS]; ++ ++ err = match_token(str, au_wbr_create_policy, args); ++ create->wbr_create = err; ++ switch (err) { ++ case AuWbrCreate_MFSRRV: ++ case AuWbrCreate_TDMFSV: ++ case AuWbrCreate_PMFSRRV: ++ e = au_wbr_mfs_wmark(&args[0], str, create); ++ if (!e) ++ e = au_wbr_mfs_sec(&args[1], str, create); ++ if (unlikely(e)) ++ err = e; ++ break; ++ case AuWbrCreate_MFSRR: ++ case AuWbrCreate_TDMFS: ++ case AuWbrCreate_PMFSRR: ++ e = au_wbr_mfs_wmark(&args[0], str, create); ++ if (unlikely(e)) { ++ err = e; ++ break; ++ } ++ fallthrough; ++ case AuWbrCreate_MFS: ++ case AuWbrCreate_PMFS: ++ create->mfs_second = AUFS_MFS_DEF_SEC; ++ break; ++ case AuWbrCreate_MFSV: ++ case AuWbrCreate_PMFSV: ++ e = au_wbr_mfs_sec(&args[0], str, create); ++ if (unlikely(e)) ++ err = e; ++ break; ++ } ++ ++ return err; ++} ++ ++const char *au_optstr_wbr_create(int wbr_create) ++{ ++ return au_parser_pattern(wbr_create, au_wbr_create_policy); ++} ++ ++static match_table_t au_wbr_copyup_policy = { ++ {AuWbrCopyup_TDP, "tdp"}, ++ {AuWbrCopyup_TDP, "top-down-parent"}, ++ {AuWbrCopyup_BUP, "bup"}, ++ {AuWbrCopyup_BUP, "bottom-up-parent"}, ++ {AuWbrCopyup_BU, "bu"}, ++ {AuWbrCopyup_BU, "bottom-up"}, ++ {-1, NULL} ++}; ++ ++int au_wbr_copyup_val(char *str) ++{ ++ substring_t args[MAX_OPT_ARGS]; ++ ++ return match_token(str, au_wbr_copyup_policy, args); ++} ++ ++const char *au_optstr_wbr_copyup(int wbr_copyup) ++{ ++ return au_parser_pattern(wbr_copyup, au_wbr_copyup_policy); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_opt_add(struct au_opt *opt, char *opt_str, unsigned long sb_flags, ++ aufs_bindex_t bindex) ++{ ++ int err; ++ struct au_opt_add *add = &opt->add; ++ char *p; ++ ++ add->bindex = bindex; ++ add->perm = AuBrPerm_RO; ++ add->pathname = opt_str; ++ p = strchr(opt_str, '='); ++ if (p) { ++ *p++ = 0; ++ if (*p) ++ add->perm = au_br_perm_val(p); ++ } ++ ++ err = vfsub_kern_path(add->pathname, AuOpt_LkupDirFlags, &add->path); ++ if (!err) { ++ if (!p) { ++ add->perm = AuBrPerm_RO; ++ if (au_test_fs_rr(add->path.dentry->d_sb)) ++ add->perm = AuBrPerm_RR; ++ else if (!bindex && !(sb_flags & SB_RDONLY)) ++ add->perm = AuBrPerm_RW; ++ } ++ opt->type = Opt_add; ++ goto out; ++ } ++ pr_err("lookup failed %s (%d)\n", add->pathname, err); ++ err = -EINVAL; ++ ++out: ++ return err; ++} ++ ++static int au_opt_wbr_create(struct super_block *sb, ++ struct au_opt_wbr_create *create) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ err = 1; /* handled */ ++ sbinfo = au_sbi(sb); ++ if (sbinfo->si_wbr_create_ops->fin) { ++ err = sbinfo->si_wbr_create_ops->fin(sb); ++ if (!err) ++ err = 1; ++ } ++ ++ sbinfo->si_wbr_create = create->wbr_create; ++ sbinfo->si_wbr_create_ops = au_wbr_create_ops + create->wbr_create; ++ switch (create->wbr_create) { ++ case AuWbrCreate_MFSRRV: ++ case AuWbrCreate_MFSRR: ++ case AuWbrCreate_TDMFS: ++ case AuWbrCreate_TDMFSV: ++ case AuWbrCreate_PMFSRR: ++ case AuWbrCreate_PMFSRRV: ++ sbinfo->si_wbr_mfs.mfsrr_watermark = create->mfsrr_watermark; ++ fallthrough; ++ case AuWbrCreate_MFS: ++ case AuWbrCreate_MFSV: ++ case AuWbrCreate_PMFS: ++ case AuWbrCreate_PMFSV: ++ sbinfo->si_wbr_mfs.mfs_expire ++ = msecs_to_jiffies(create->mfs_second * MSEC_PER_SEC); ++ break; ++ } ++ ++ if (sbinfo->si_wbr_create_ops->init) ++ sbinfo->si_wbr_create_ops->init(sb); /* ignore */ ++ ++ return err; ++} ++ ++/* ++ * returns, ++ * plus: processed without an error ++ * zero: unprocessed ++ */ ++static int au_opt_simple(struct super_block *sb, struct au_opt *opt, ++ struct au_opts *opts) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ err = 1; /* handled */ ++ sbinfo = au_sbi(sb); ++ switch (opt->type) { ++ case Opt_udba: ++ sbinfo->si_mntflags &= ~AuOptMask_UDBA; ++ sbinfo->si_mntflags |= opt->udba; ++ opts->given_udba |= opt->udba; ++ break; ++ ++ case Opt_plink: ++ if (opt->tf) ++ au_opt_set(sbinfo->si_mntflags, PLINK); ++ else { ++ if (au_opt_test(sbinfo->si_mntflags, PLINK)) ++ au_plink_put(sb, /*verbose*/1); ++ au_opt_clr(sbinfo->si_mntflags, PLINK); ++ } ++ break; ++ case Opt_list_plink: ++ if (au_opt_test(sbinfo->si_mntflags, PLINK)) ++ au_plink_list(sb); ++ break; ++ ++ case Opt_dio: ++ if (opt->tf) { ++ au_opt_set(sbinfo->si_mntflags, DIO); ++ au_fset_opts(opts->flags, REFRESH_DYAOP); ++ } else { ++ au_opt_clr(sbinfo->si_mntflags, DIO); ++ au_fset_opts(opts->flags, REFRESH_DYAOP); ++ } ++ break; ++ ++ case Opt_fhsm_sec: ++ au_fhsm_set(sbinfo, opt->fhsm_second); ++ break; ++ ++ case Opt_diropq_a: ++ au_opt_set(sbinfo->si_mntflags, ALWAYS_DIROPQ); ++ break; ++ case Opt_diropq_w: ++ au_opt_clr(sbinfo->si_mntflags, ALWAYS_DIROPQ); ++ break; ++ ++ case Opt_warn_perm: ++ if (opt->tf) ++ au_opt_set(sbinfo->si_mntflags, WARN_PERM); ++ else ++ au_opt_clr(sbinfo->si_mntflags, WARN_PERM); ++ break; ++ ++ case Opt_verbose: ++ if (opt->tf) ++ au_opt_set(sbinfo->si_mntflags, VERBOSE); ++ else ++ au_opt_clr(sbinfo->si_mntflags, VERBOSE); ++ break; ++ ++ case Opt_sum: ++ if (opt->tf) ++ au_opt_set(sbinfo->si_mntflags, SUM); ++ else { ++ au_opt_clr(sbinfo->si_mntflags, SUM); ++ au_opt_clr(sbinfo->si_mntflags, SUM_W); ++ } ++ break; ++ case Opt_wsum: ++ au_opt_clr(sbinfo->si_mntflags, SUM); ++ au_opt_set(sbinfo->si_mntflags, SUM_W); ++ break; ++ ++ case Opt_wbr_create: ++ err = au_opt_wbr_create(sb, &opt->wbr_create); ++ break; ++ case Opt_wbr_copyup: ++ sbinfo->si_wbr_copyup = opt->wbr_copyup; ++ sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + opt->wbr_copyup; ++ break; ++ ++ case Opt_dirwh: ++ sbinfo->si_dirwh = opt->dirwh; ++ break; ++ ++ case Opt_rdcache: ++ sbinfo->si_rdcache ++ = msecs_to_jiffies(opt->rdcache * MSEC_PER_SEC); ++ break; ++ case Opt_rdblk: ++ sbinfo->si_rdblk = opt->rdblk; ++ break; ++ case Opt_rdhash: ++ sbinfo->si_rdhash = opt->rdhash; ++ break; ++ ++ case Opt_shwh: ++ if (opt->tf) ++ au_opt_set(sbinfo->si_mntflags, SHWH); ++ else ++ au_opt_clr(sbinfo->si_mntflags, SHWH); ++ break; ++ ++ case Opt_dirperm1: ++ if (opt->tf) ++ au_opt_set(sbinfo->si_mntflags, DIRPERM1); ++ else ++ au_opt_clr(sbinfo->si_mntflags, DIRPERM1); ++ break; ++ ++ case Opt_trunc_xino: ++ if (opt->tf) ++ au_opt_set(sbinfo->si_mntflags, TRUNC_XINO); ++ else ++ au_opt_clr(sbinfo->si_mntflags, TRUNC_XINO); ++ break; ++ ++ case Opt_trunc_xino_path: ++ case Opt_itrunc_xino: ++ err = au_xino_trunc(sb, opt->xino_itrunc.bindex, ++ /*idx_begin*/0); ++ if (!err) ++ err = 1; ++ break; ++ ++ case Opt_trunc_xib: ++ if (opt->tf) ++ au_fset_opts(opts->flags, TRUNC_XIB); ++ else ++ au_fclr_opts(opts->flags, TRUNC_XIB); ++ break; ++ ++ case Opt_dirren: ++ err = 1; ++ if (opt->tf) { ++ if (!au_opt_test(sbinfo->si_mntflags, DIRREN)) { ++ err = au_dr_opt_set(sb); ++ if (!err) ++ err = 1; ++ } ++ if (err == 1) ++ au_opt_set(sbinfo->si_mntflags, DIRREN); ++ } else { ++ if (au_opt_test(sbinfo->si_mntflags, DIRREN)) { ++ err = au_dr_opt_clr(sb, au_ftest_opts(opts->flags, ++ DR_FLUSHED)); ++ if (!err) ++ err = 1; ++ } ++ if (err == 1) ++ au_opt_clr(sbinfo->si_mntflags, DIRREN); ++ } ++ break; ++ ++ case Opt_acl: ++ if (opt->tf) ++ sb->s_flags |= SB_POSIXACL; ++ else ++ sb->s_flags &= ~SB_POSIXACL; ++ break; ++ ++ default: ++ err = 0; ++ break; ++ } ++ ++ return err; ++} ++ ++/* ++ * returns tri-state. ++ * plus: processed without an error ++ * zero: unprocessed ++ * minus: error ++ */ ++static int au_opt_br(struct super_block *sb, struct au_opt *opt, ++ struct au_opts *opts) ++{ ++ int err, do_refresh; ++ ++ err = 0; ++ switch (opt->type) { ++ case Opt_append: ++ opt->add.bindex = au_sbbot(sb) + 1; ++ if (opt->add.bindex < 0) ++ opt->add.bindex = 0; ++ goto add; ++ /* Always goto add, not fallthrough */ ++ case Opt_prepend: ++ opt->add.bindex = 0; ++ fallthrough; ++ add: /* indented label */ ++ case Opt_add: ++ err = au_br_add(sb, &opt->add, ++ au_ftest_opts(opts->flags, REMOUNT)); ++ if (!err) { ++ err = 1; ++ au_fset_opts(opts->flags, REFRESH); ++ } ++ break; ++ ++ case Opt_del: ++ case Opt_idel: ++ err = au_br_del(sb, &opt->del, ++ au_ftest_opts(opts->flags, REMOUNT)); ++ if (!err) { ++ err = 1; ++ au_fset_opts(opts->flags, TRUNC_XIB); ++ au_fset_opts(opts->flags, REFRESH); ++ } ++ break; ++ ++ case Opt_mod: ++ case Opt_imod: ++ err = au_br_mod(sb, &opt->mod, ++ au_ftest_opts(opts->flags, REMOUNT), ++ &do_refresh); ++ if (!err) { ++ err = 1; ++ if (do_refresh) ++ au_fset_opts(opts->flags, REFRESH); ++ } ++ break; ++ } ++ return err; ++} ++ ++static int au_opt_xino(struct super_block *sb, struct au_opt *opt, ++ struct au_opt_xino **opt_xino, ++ struct au_opts *opts) ++{ ++ int err; ++ ++ err = 0; ++ switch (opt->type) { ++ case Opt_xino: ++ err = au_xino_set(sb, &opt->xino, ++ !!au_ftest_opts(opts->flags, REMOUNT)); ++ if (!err) ++ *opt_xino = &opt->xino; ++ break; ++ case Opt_noxino: ++ au_xino_clr(sb); ++ *opt_xino = (void *)-1; ++ break; ++ } ++ ++ return err; ++} ++ ++int au_opts_verify(struct super_block *sb, unsigned long sb_flags, ++ unsigned int pending) ++{ ++ int err, fhsm; ++ aufs_bindex_t bindex, bbot; ++ unsigned char do_plink, skip, do_free, can_no_dreval; ++ struct au_branch *br; ++ struct au_wbr *wbr; ++ struct dentry *root, *dentry; ++ struct inode *dir, *h_dir; ++ struct au_sbinfo *sbinfo; ++ struct au_hinode *hdir; ++ ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!(sbinfo->si_mntflags & AuOptMask_UDBA)); ++ ++ if (!(sb_flags & SB_RDONLY)) { ++ if (unlikely(!au_br_writable(au_sbr_perm(sb, 0)))) ++ pr_warn("first branch should be rw\n"); ++ if (unlikely(au_opt_test(sbinfo->si_mntflags, SHWH))) ++ pr_warn_once("shwh should be used with ro\n"); ++ } ++ ++ if (au_opt_test((sbinfo->si_mntflags | pending), UDBA_HNOTIFY) ++ && !au_opt_test(sbinfo->si_mntflags, XINO)) ++ pr_warn_once("udba=*notify requires xino\n"); ++ ++ if (au_opt_test(sbinfo->si_mntflags, DIRPERM1)) ++ pr_warn_once("dirperm1 breaks the protection" ++ " by the permission bits on the lower branch\n"); ++ ++ err = 0; ++ fhsm = 0; ++ root = sb->s_root; ++ dir = d_inode(root); ++ do_plink = !!au_opt_test(sbinfo->si_mntflags, PLINK); ++ can_no_dreval = !!au_opt_test((sbinfo->si_mntflags | pending), ++ UDBA_NONE); ++ bbot = au_sbbot(sb); ++ for (bindex = 0; !err && bindex <= bbot; bindex++) { ++ skip = 0; ++ h_dir = au_h_iptr(dir, bindex); ++ br = au_sbr(sb, bindex); ++ ++ if ((br->br_perm & AuBrAttr_ICEX) ++ && !h_dir->i_op->listxattr) ++ br->br_perm &= ~AuBrAttr_ICEX; ++#if 0 /* untested */ ++ if ((br->br_perm & AuBrAttr_ICEX_SEC) ++ && (au_br_sb(br)->s_flags & SB_NOSEC)) ++ br->br_perm &= ~AuBrAttr_ICEX_SEC; ++#endif ++ ++ do_free = 0; ++ wbr = br->br_wbr; ++ if (wbr) ++ wbr_wh_read_lock(wbr); ++ ++ if (!au_br_writable(br->br_perm)) { ++ do_free = !!wbr; ++ skip = (!wbr ++ || (!wbr->wbr_whbase ++ && !wbr->wbr_plink ++ && !wbr->wbr_orph)); ++ } else if (!au_br_wh_linkable(br->br_perm)) { ++ /* skip = (!br->br_whbase && !br->br_orph); */ ++ skip = (!wbr || !wbr->wbr_whbase); ++ if (skip && wbr) { ++ if (do_plink) ++ skip = !!wbr->wbr_plink; ++ else ++ skip = !wbr->wbr_plink; ++ } ++ } else { ++ /* skip = (br->br_whbase && br->br_ohph); */ ++ skip = (wbr && wbr->wbr_whbase); ++ if (skip) { ++ if (do_plink) ++ skip = !!wbr->wbr_plink; ++ else ++ skip = !wbr->wbr_plink; ++ } ++ } ++ if (wbr) ++ wbr_wh_read_unlock(wbr); ++ ++ if (can_no_dreval) { ++ dentry = br->br_path.dentry; ++ spin_lock(&dentry->d_lock); ++ if (dentry->d_flags & ++ (DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE)) ++ can_no_dreval = 0; ++ spin_unlock(&dentry->d_lock); ++ } ++ ++ if (au_br_fhsm(br->br_perm)) { ++ fhsm++; ++ AuDebugOn(!br->br_fhsm); ++ } ++ ++ if (skip) ++ continue; ++ ++ hdir = au_hi(dir, bindex); ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ if (wbr) ++ wbr_wh_write_lock(wbr); ++ err = au_wh_init(br, sb); ++ if (wbr) ++ wbr_wh_write_unlock(wbr); ++ au_hn_inode_unlock(hdir); ++ ++ if (!err && do_free) { ++ au_kfree_rcu(wbr); ++ br->br_wbr = NULL; ++ } ++ } ++ ++ if (can_no_dreval) ++ au_fset_si(sbinfo, NO_DREVAL); ++ else ++ au_fclr_si(sbinfo, NO_DREVAL); ++ ++ if (fhsm >= 2) { ++ au_fset_si(sbinfo, FHSM); ++ for (bindex = bbot; bindex >= 0; bindex--) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm)) { ++ au_fhsm_set_bottom(sb, bindex); ++ break; ++ } ++ } ++ } else { ++ au_fclr_si(sbinfo, FHSM); ++ au_fhsm_set_bottom(sb, -1); ++ } ++ ++ return err; ++} ++ ++int au_opts_mount(struct super_block *sb, struct au_opts *opts) ++{ ++ int err; ++ unsigned int tmp; ++ aufs_bindex_t bindex, bbot; ++ struct au_opt *opt; ++ struct au_opt_xino *opt_xino, xino; ++ struct au_sbinfo *sbinfo; ++ struct au_branch *br; ++ struct inode *dir; ++ ++ SiMustWriteLock(sb); ++ ++ err = 0; ++ opt_xino = NULL; ++ opt = opts->opt; ++ while (err >= 0 && opt->type != Opt_tail) ++ err = au_opt_simple(sb, opt++, opts); ++ if (err > 0) ++ err = 0; ++ else if (unlikely(err < 0)) ++ goto out; ++ ++ /* disable xino and udba temporary */ ++ sbinfo = au_sbi(sb); ++ tmp = sbinfo->si_mntflags; ++ au_opt_clr(sbinfo->si_mntflags, XINO); ++ au_opt_set_udba(sbinfo->si_mntflags, UDBA_REVAL); ++ ++ opt = opts->opt; ++ while (err >= 0 && opt->type != Opt_tail) ++ err = au_opt_br(sb, opt++, opts); ++ if (err > 0) ++ err = 0; ++ else if (unlikely(err < 0)) ++ goto out; ++ ++ bbot = au_sbbot(sb); ++ if (unlikely(bbot < 0)) { ++ err = -EINVAL; ++ pr_err("no branches\n"); ++ goto out; ++ } ++ ++ if (au_opt_test(tmp, XINO)) ++ au_opt_set(sbinfo->si_mntflags, XINO); ++ opt = opts->opt; ++ while (!err && opt->type != Opt_tail) ++ err = au_opt_xino(sb, opt++, &opt_xino, opts); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_opts_verify(sb, sb->s_flags, tmp); ++ if (unlikely(err)) ++ goto out; ++ ++ /* restore xino */ ++ if (au_opt_test(tmp, XINO) && !opt_xino) { ++ xino.file = au_xino_def(sb); ++ err = PTR_ERR(xino.file); ++ if (IS_ERR(xino.file)) ++ goto out; ++ ++ err = au_xino_set(sb, &xino, /*remount*/0); ++ fput(xino.file); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ /* restore udba */ ++ tmp &= AuOptMask_UDBA; ++ sbinfo->si_mntflags &= ~AuOptMask_UDBA; ++ sbinfo->si_mntflags |= tmp; ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ err = au_hnotify_reset_br(tmp, br, br->br_perm); ++ if (unlikely(err)) ++ AuIOErr("hnotify failed on br %d, %d, ignored\n", ++ bindex, err); ++ /* go on even if err */ ++ } ++ if (au_opt_test(tmp, UDBA_HNOTIFY)) { ++ dir = d_inode(sb->s_root); ++ au_hn_reset(dir, au_hi_flags(dir, /*isdir*/1) & ~AuHi_XINO); ++ } ++ ++out: ++ return err; ++} ++ ++int au_opts_remount(struct super_block *sb, struct au_opts *opts) ++{ ++ int err, rerr; ++ unsigned char no_dreval; ++ struct inode *dir; ++ struct au_opt_xino *opt_xino; ++ struct au_opt *opt; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ err = au_dr_opt_flush(sb); ++ if (unlikely(err)) ++ goto out; ++ au_fset_opts(opts->flags, DR_FLUSHED); ++ ++ dir = d_inode(sb->s_root); ++ sbinfo = au_sbi(sb); ++ opt_xino = NULL; ++ opt = opts->opt; ++ while (err >= 0 && opt->type != Opt_tail) { ++ err = au_opt_simple(sb, opt, opts); ++ if (!err) ++ err = au_opt_br(sb, opt, opts); ++ if (!err) ++ err = au_opt_xino(sb, opt, &opt_xino, opts); ++ opt++; ++ } ++ if (err > 0) ++ err = 0; ++ AuTraceErr(err); ++ /* go on even err */ ++ ++ no_dreval = !!au_ftest_si(sbinfo, NO_DREVAL); ++ rerr = au_opts_verify(sb, opts->sb_flags, /*pending*/0); ++ if (unlikely(rerr && !err)) ++ err = rerr; ++ ++ if (no_dreval != !!au_ftest_si(sbinfo, NO_DREVAL)) ++ au_fset_opts(opts->flags, REFRESH_IDOP); ++ ++ if (au_ftest_opts(opts->flags, TRUNC_XIB)) { ++ rerr = au_xib_trunc(sb); ++ if (unlikely(rerr && !err)) ++ err = rerr; ++ } ++ ++ /* will be handled by the caller */ ++ if (!au_ftest_opts(opts->flags, REFRESH) ++ && (opts->given_udba ++ || au_opt_test(sbinfo->si_mntflags, XINO) ++ || au_ftest_opts(opts->flags, REFRESH_IDOP) ++ )) ++ au_fset_opts(opts->flags, REFRESH); ++ ++ AuDbg("status 0x%x\n", opts->flags); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++unsigned int au_opt_udba(struct super_block *sb) ++{ ++ return au_mntflags(sb) & AuOptMask_UDBA; ++} +diff -Nurp linux-5.15.37/fs/aufs/opts.h linux-5.15.37-aufs/fs/aufs/opts.h +--- linux-5.15.37/fs/aufs/opts.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/opts.h 2022-04-08 20:22:30.615616621 +0300 +@@ -0,0 +1,250 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * mount options/flags ++ */ ++ ++#ifndef __AUFS_OPTS_H__ ++#define __AUFS_OPTS_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++ ++enum { ++ Opt_br, ++ Opt_add, Opt_del, Opt_mod, Opt_append, Opt_prepend, ++ Opt_idel, Opt_imod, ++ Opt_dirwh, Opt_rdcache, Opt_rdblk, Opt_rdhash, ++ Opt_xino, Opt_noxino, ++ Opt_trunc_xino, Opt_trunc_xino_v, ++ Opt_trunc_xino_path, Opt_itrunc_xino, ++ Opt_trunc_xib, ++ Opt_shwh, ++ Opt_plink, Opt_list_plink, ++ Opt_udba, ++ Opt_dio, ++ Opt_diropq, Opt_diropq_a, Opt_diropq_w, ++ Opt_warn_perm, ++ Opt_wbr_copyup, Opt_wbr_create, ++ Opt_fhsm_sec, ++ Opt_verbose, Opt_noverbose, ++ Opt_sum, Opt_wsum, ++ Opt_dirperm1, ++ Opt_dirren, ++ Opt_acl, ++ Opt_tail, Opt_ignore, Opt_ignore_silent, Opt_err ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* mount flags */ ++#define AuOpt_XINO 1 /* external inode number bitmap ++ and translation table */ ++#define AuOpt_TRUNC_XINO (1 << 1) /* truncate xino files */ ++#define AuOpt_UDBA_NONE (1 << 2) /* users direct branch access */ ++#define AuOpt_UDBA_REVAL (1 << 3) ++#define AuOpt_UDBA_HNOTIFY (1 << 4) ++#define AuOpt_SHWH (1 << 5) /* show whiteout */ ++#define AuOpt_PLINK (1 << 6) /* pseudo-link */ ++#define AuOpt_DIRPERM1 (1 << 7) /* ignore the lower dir's perm ++ bits */ ++#define AuOpt_ALWAYS_DIROPQ (1 << 9) /* policy to creating diropq */ ++#define AuOpt_SUM (1 << 10) /* summation for statfs(2) */ ++#define AuOpt_SUM_W (1 << 11) /* unimplemented */ ++#define AuOpt_WARN_PERM (1 << 12) /* warn when add-branch */ ++#define AuOpt_VERBOSE (1 << 13) /* print the cause of error */ ++#define AuOpt_DIO (1 << 14) /* direct io */ ++#define AuOpt_DIRREN (1 << 15) /* directory rename */ ++ ++#ifndef CONFIG_AUFS_HNOTIFY ++#undef AuOpt_UDBA_HNOTIFY ++#define AuOpt_UDBA_HNOTIFY 0 ++#endif ++#ifndef CONFIG_AUFS_DIRREN ++#undef AuOpt_DIRREN ++#define AuOpt_DIRREN 0 ++#endif ++#ifndef CONFIG_AUFS_SHWH ++#undef AuOpt_SHWH ++#define AuOpt_SHWH 0 ++#endif ++ ++#define AuOpt_Def (AuOpt_XINO \ ++ | AuOpt_UDBA_REVAL \ ++ | AuOpt_PLINK \ ++ /* | AuOpt_DIRPERM1 */ \ ++ | AuOpt_WARN_PERM) ++#define AuOptMask_UDBA (AuOpt_UDBA_NONE \ ++ | AuOpt_UDBA_REVAL \ ++ | AuOpt_UDBA_HNOTIFY) ++ ++#define AuOpt_LkupDirFlags (LOOKUP_FOLLOW | LOOKUP_DIRECTORY) ++ ++#define au_opt_test(flags, name) (flags & AuOpt_##name) ++#define au_opt_set(flags, name) do { \ ++ BUILD_BUG_ON(AuOpt_##name & AuOptMask_UDBA); \ ++ ((flags) |= AuOpt_##name); \ ++} while (0) ++#define au_opt_set_udba(flags, name) do { \ ++ (flags) &= ~AuOptMask_UDBA; \ ++ ((flags) |= AuOpt_##name); \ ++} while (0) ++#define au_opt_clr(flags, name) do { \ ++ ((flags) &= ~AuOpt_##name); \ ++} while (0) ++ ++static inline unsigned int au_opts_plink(unsigned int mntflags) ++{ ++#ifdef CONFIG_PROC_FS ++ return mntflags; ++#else ++ return mntflags & ~AuOpt_PLINK; ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policies to select one among multiple writable branches */ ++enum { ++ AuWbrCreate_TDP, /* top down parent */ ++ AuWbrCreate_RR, /* round robin */ ++ AuWbrCreate_MFS, /* most free space */ ++ AuWbrCreate_MFSV, /* mfs with seconds */ ++ AuWbrCreate_MFSRR, /* mfs then rr */ ++ AuWbrCreate_MFSRRV, /* mfs then rr with seconds */ ++ AuWbrCreate_TDMFS, /* top down regardless parent and mfs */ ++ AuWbrCreate_TDMFSV, /* top down regardless parent and mfs */ ++ AuWbrCreate_PMFS, /* parent and mfs */ ++ AuWbrCreate_PMFSV, /* parent and mfs with seconds */ ++ AuWbrCreate_PMFSRR, /* parent, mfs and round-robin */ ++ AuWbrCreate_PMFSRRV, /* plus seconds */ ++ ++ AuWbrCreate_Def = AuWbrCreate_TDP ++}; ++ ++enum { ++ AuWbrCopyup_TDP, /* top down parent */ ++ AuWbrCopyup_BUP, /* bottom up parent */ ++ AuWbrCopyup_BU, /* bottom up */ ++ ++ AuWbrCopyup_Def = AuWbrCopyup_TDP ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct file; ++ ++struct au_opt_add { ++ aufs_bindex_t bindex; ++ char *pathname; ++ int perm; ++ struct path path; ++}; ++ ++struct au_opt_del { ++ char *pathname; ++ struct path h_path; ++}; ++ ++struct au_opt_mod { ++ char *path; ++ int perm; ++ struct dentry *h_root; ++}; ++ ++struct au_opt_xino { ++ char *path; ++ struct file *file; ++}; ++ ++struct au_opt_xino_itrunc { ++ aufs_bindex_t bindex; ++}; ++ ++struct au_opt_wbr_create { ++ int wbr_create; ++ int mfs_second; ++ unsigned long long mfsrr_watermark; ++}; ++ ++struct au_opt { ++ int type; ++ union { ++ struct au_opt_xino xino; ++ struct au_opt_xino_itrunc xino_itrunc; ++ struct au_opt_add add; ++ struct au_opt_del del; ++ struct au_opt_mod mod; ++ int dirwh; ++ int rdcache; ++ unsigned int rdblk; ++ unsigned int rdhash; ++ int udba; ++ struct au_opt_wbr_create wbr_create; ++ int wbr_copyup; ++ unsigned int fhsm_second; ++ bool tf; /* generic flag, true or false */ ++ }; ++}; ++ ++/* opts flags */ ++#define AuOpts_REMOUNT 1 ++#define AuOpts_REFRESH (1 << 1) ++#define AuOpts_TRUNC_XIB (1 << 2) ++#define AuOpts_REFRESH_DYAOP (1 << 3) ++#define AuOpts_REFRESH_IDOP (1 << 4) ++#define AuOpts_DR_FLUSHED (1 << 5) ++#define au_ftest_opts(flags, name) ((flags) & AuOpts_##name) ++#define au_fset_opts(flags, name) \ ++ do { (flags) |= AuOpts_##name; } while (0) ++#define au_fclr_opts(flags, name) \ ++ do { (flags) &= ~AuOpts_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_DIRREN ++#undef AuOpts_DR_FLUSHED ++#define AuOpts_DR_FLUSHED 0 ++#endif ++ ++struct au_opts { ++ struct au_opt *opt; ++ int max_opt; ++ ++ unsigned int given_udba; ++ unsigned int flags; ++ unsigned long sb_flags; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* opts.c */ ++int au_br_perm_val(char *perm); ++void au_optstr_br_perm(au_br_perm_str_t *str, int perm); ++int au_udba_val(char *str); ++const char *au_optstr_udba(int udba); ++int au_wbr_create_val(char *str, struct au_opt_wbr_create *create); ++const char *au_optstr_wbr_create(int wbr_create); ++int au_wbr_copyup_val(char *str); ++const char *au_optstr_wbr_copyup(int wbr_copyup); ++ ++int au_opt_add(struct au_opt *opt, char *opt_str, unsigned long sb_flags, ++ aufs_bindex_t bindex); ++struct super_block; ++int au_opts_verify(struct super_block *sb, unsigned long sb_flags, ++ unsigned int pending); ++int au_opts_mount(struct super_block *sb, struct au_opts *opts); ++int au_opts_remount(struct super_block *sb, struct au_opts *opts); ++ ++unsigned int au_opt_udba(struct super_block *sb); ++ ++/* fsctx.c */ ++int aufs_fsctx_init(struct fs_context *fc); ++extern const struct fs_parameter_spec aufs_fsctx_paramspec[]; ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_OPTS_H__ */ +diff -Nurp linux-5.15.37/fs/aufs/plink.c linux-5.15.37-aufs/fs/aufs/plink.c +--- linux-5.15.37/fs/aufs/plink.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/plink.c 2022-04-08 20:22:30.615616621 +0300 +@@ -0,0 +1,503 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * pseudo-link ++ */ ++ ++#include "aufs.h" ++ ++/* ++ * the pseudo-link maintenance mode. ++ * during a user process maintains the pseudo-links, ++ * prohibit adding a new plink and branch manipulation. ++ * ++ * Flags ++ * NOPLM: ++ * For entry functions which will handle plink, and i_mutex is already held ++ * in VFS. ++ * They cannot wait and should return an error at once. ++ * Callers has to check the error. ++ * NOPLMW: ++ * For entry functions which will handle plink, but i_mutex is not held ++ * in VFS. ++ * They can wait the plink maintenance mode to finish. ++ * ++ * They behave like F_SETLK and F_SETLKW. ++ * If the caller never handle plink, then both flags are unnecessary. ++ */ ++ ++int au_plink_maint(struct super_block *sb, int flags) ++{ ++ int err; ++ pid_t pid, ppid; ++ struct task_struct *parent, *prev; ++ struct au_sbinfo *sbi; ++ ++ SiMustAnyLock(sb); ++ ++ err = 0; ++ if (!au_opt_test(au_mntflags(sb), PLINK)) ++ goto out; ++ ++ sbi = au_sbi(sb); ++ pid = sbi->si_plink_maint_pid; ++ if (!pid || pid == current->pid) ++ goto out; ++ ++ /* todo: it highly depends upon /sbin/mount.aufs */ ++ prev = NULL; ++ parent = current; ++ ppid = 0; ++ rcu_read_lock(); ++ while (1) { ++ parent = rcu_dereference(parent->real_parent); ++ if (parent == prev) ++ break; ++ ppid = task_pid_vnr(parent); ++ if (pid == ppid) { ++ rcu_read_unlock(); ++ goto out; ++ } ++ prev = parent; ++ } ++ rcu_read_unlock(); ++ ++ if (au_ftest_lock(flags, NOPLMW)) { ++ /* if there is no i_mutex lock in VFS, we don't need to wait */ ++ /* AuDebugOn(!lockdep_depth(current)); */ ++ while (sbi->si_plink_maint_pid) { ++ si_read_unlock(sb); ++ /* gave up wake_up_bit() */ ++ wait_event(sbi->si_plink_wq, !sbi->si_plink_maint_pid); ++ ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&sbi->si_nowait); ++ si_noflush_read_lock(sb); ++ } ++ } else if (au_ftest_lock(flags, NOPLM)) { ++ AuDbg("ppid %d, pid %d\n", ppid, pid); ++ err = -EAGAIN; ++ } ++ ++out: ++ return err; ++} ++ ++void au_plink_maint_leave(struct au_sbinfo *sbinfo) ++{ ++ spin_lock(&sbinfo->si_plink_maint_lock); ++ sbinfo->si_plink_maint_pid = 0; ++ spin_unlock(&sbinfo->si_plink_maint_lock); ++ wake_up_all(&sbinfo->si_plink_wq); ++} ++ ++int au_plink_maint_enter(struct super_block *sb) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ /* make sure i am the only one in this fs */ ++ si_write_lock(sb, AuLock_FLUSH); ++ if (au_opt_test(au_mntflags(sb), PLINK)) { ++ spin_lock(&sbinfo->si_plink_maint_lock); ++ if (!sbinfo->si_plink_maint_pid) ++ sbinfo->si_plink_maint_pid = current->pid; ++ else ++ err = -EBUSY; ++ spin_unlock(&sbinfo->si_plink_maint_lock); ++ } ++ si_write_unlock(sb); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_DEBUG ++void au_plink_list(struct super_block *sb) ++{ ++ int i; ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_icntnr *icntnr; ++ ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); ++ ++ for (i = 0; i < AuPlink_NHASH; i++) { ++ hbl = sbinfo->si_plink + i; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(icntnr, pos, hbl, plink) ++ AuDbg("%lu\n", icntnr->vfs_inode.i_ino); ++ hlist_bl_unlock(hbl); ++ } ++} ++#endif ++ ++/* is the inode pseudo-linked? */ ++int au_plink_test(struct inode *inode) ++{ ++ int found, i; ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_icntnr *icntnr; ++ ++ sbinfo = au_sbi(inode->i_sb); ++ AuRwMustAnyLock(&sbinfo->si_rwsem); ++ AuDebugOn(!au_opt_test(au_mntflags(inode->i_sb), PLINK)); ++ AuDebugOn(au_plink_maint(inode->i_sb, AuLock_NOPLM)); ++ ++ found = 0; ++ i = au_plink_hash(inode->i_ino); ++ hbl = sbinfo->si_plink + i; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(icntnr, pos, hbl, plink) ++ if (&icntnr->vfs_inode == inode) { ++ found = 1; ++ break; ++ } ++ hlist_bl_unlock(hbl); ++ return found; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * generate a name for plink. ++ * the file will be stored under AUFS_WH_PLINKDIR. ++ */ ++/* 20 is max digits length of ulong 64 */ ++#define PLINK_NAME_LEN ((20 + 1) * 2) ++ ++static int plink_name(char *name, int len, struct inode *inode, ++ aufs_bindex_t bindex) ++{ ++ int rlen; ++ struct inode *h_inode; ++ ++ h_inode = au_h_iptr(inode, bindex); ++ rlen = snprintf(name, len, "%lu.%lu", inode->i_ino, h_inode->i_ino); ++ return rlen; ++} ++ ++struct au_do_plink_lkup_args { ++ struct dentry **errp; ++ struct qstr *tgtname; ++ struct path *h_ppath; ++}; ++ ++static struct dentry *au_do_plink_lkup(struct qstr *tgtname, ++ struct path *h_ppath) ++{ ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ ++ h_inode = d_inode(h_ppath->dentry); ++ inode_lock_shared_nested(h_inode, AuLsc_I_CHILD2); ++ h_dentry = vfsub_lkup_one(tgtname, h_ppath); ++ inode_unlock_shared(h_inode); ++ ++ return h_dentry; ++} ++ ++static void au_call_do_plink_lkup(void *args) ++{ ++ struct au_do_plink_lkup_args *a = args; ++ *a->errp = au_do_plink_lkup(a->tgtname, a->h_ppath); ++} ++ ++/* lookup the plink-ed @inode under the branch at @bindex */ ++struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex) ++{ ++ struct dentry *h_dentry; ++ struct au_branch *br; ++ struct path h_ppath; ++ int wkq_err; ++ char a[PLINK_NAME_LEN]; ++ struct qstr tgtname = QSTR_INIT(a, 0); ++ ++ AuDebugOn(au_plink_maint(inode->i_sb, AuLock_NOPLM)); ++ ++ br = au_sbr(inode->i_sb, bindex); ++ h_ppath.dentry = br->br_wbr->wbr_plink; ++ h_ppath.mnt = au_br_mnt(br); ++ tgtname.len = plink_name(a, sizeof(a), inode, bindex); ++ ++ if (!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) { ++ struct au_do_plink_lkup_args args = { ++ .errp = &h_dentry, ++ .tgtname = &tgtname, ++ .h_ppath = &h_ppath ++ }; ++ ++ wkq_err = au_wkq_wait(au_call_do_plink_lkup, &args); ++ if (unlikely(wkq_err)) ++ h_dentry = ERR_PTR(wkq_err); ++ } else ++ h_dentry = au_do_plink_lkup(&tgtname, &h_ppath); ++ ++ return h_dentry; ++} ++ ++/* create a pseudo-link */ ++static int do_whplink(struct qstr *tgt, struct path *h_ppath, ++ struct dentry *h_dentry) ++{ ++ int err; ++ struct path h_path; ++ struct inode *h_dir, *delegated; ++ ++ h_dir = d_inode(h_ppath->dentry); ++ inode_lock_nested(h_dir, AuLsc_I_CHILD2); ++ h_path.mnt = h_ppath->mnt; ++again: ++ h_path.dentry = vfsub_lkup_one(tgt, h_ppath); ++ err = PTR_ERR(h_path.dentry); ++ if (IS_ERR(h_path.dentry)) ++ goto out; ++ ++ err = 0; ++ /* wh.plink dir is not monitored */ ++ /* todo: is it really safe? */ ++ if (d_is_positive(h_path.dentry) ++ && d_inode(h_path.dentry) != d_inode(h_dentry)) { ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, &h_path, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ dput(h_path.dentry); ++ h_path.dentry = NULL; ++ if (!err) ++ goto again; ++ } ++ if (!err && d_is_negative(h_path.dentry)) { ++ delegated = NULL; ++ err = vfsub_link(h_dentry, h_dir, &h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ } ++ dput(h_path.dentry); ++ ++out: ++ inode_unlock(h_dir); ++ return err; ++} ++ ++struct do_whplink_args { ++ int *errp; ++ struct qstr *tgt; ++ struct path *h_ppath; ++ struct dentry *h_dentry; ++}; ++ ++static void call_do_whplink(void *args) ++{ ++ struct do_whplink_args *a = args; ++ *a->errp = do_whplink(a->tgt, a->h_ppath, a->h_dentry); ++} ++ ++static int whplink(struct dentry *h_dentry, struct inode *inode, ++ aufs_bindex_t bindex) ++{ ++ int err, wkq_err; ++ struct au_branch *br; ++ struct au_wbr *wbr; ++ struct path h_ppath; ++ char a[PLINK_NAME_LEN]; ++ struct qstr tgtname = QSTR_INIT(a, 0); ++ ++ br = au_sbr(inode->i_sb, bindex); ++ wbr = br->br_wbr; ++ h_ppath.dentry = wbr->wbr_plink; ++ h_ppath.mnt = au_br_mnt(br); ++ tgtname.len = plink_name(a, sizeof(a), inode, bindex); ++ ++ /* always superio. */ ++ if (!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) { ++ struct do_whplink_args args = { ++ .errp = &err, ++ .tgt = &tgtname, ++ .h_ppath = &h_ppath, ++ .h_dentry = h_dentry ++ }; ++ wkq_err = au_wkq_wait(call_do_whplink, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } else ++ err = do_whplink(&tgtname, &h_ppath, h_dentry); ++ ++ return err; ++} ++ ++/* ++ * create a new pseudo-link for @h_dentry on @bindex. ++ * the linked inode is held in aufs @inode. ++ */ ++void au_plink_append(struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_dentry) ++{ ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_icntnr *icntnr; ++ int found, err, cnt, i; ++ ++ sb = inode->i_sb; ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); ++ ++ found = au_plink_test(inode); ++ if (found) ++ return; ++ ++ i = au_plink_hash(inode->i_ino); ++ hbl = sbinfo->si_plink + i; ++ au_igrab(inode); ++ ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(icntnr, pos, hbl, plink) { ++ if (&icntnr->vfs_inode == inode) { ++ found = 1; ++ break; ++ } ++ } ++ if (!found) { ++ icntnr = container_of(inode, struct au_icntnr, vfs_inode); ++ hlist_bl_add_head(&icntnr->plink, hbl); ++ } ++ hlist_bl_unlock(hbl); ++ if (!found) { ++ cnt = au_hbl_count(hbl); ++#define msg "unexpectedly unbalanced or too many pseudo-links" ++ if (cnt > AUFS_PLINK_WARN) ++ AuWarn1(msg ", %d\n", cnt); ++#undef msg ++ err = whplink(h_dentry, inode, bindex); ++ if (unlikely(err)) { ++ pr_warn("err %d, damaged pseudo link.\n", err); ++ au_hbl_del(&icntnr->plink, hbl); ++ iput(&icntnr->vfs_inode); ++ } ++ } else ++ iput(&icntnr->vfs_inode); ++} ++ ++/* free all plinks */ ++void au_plink_put(struct super_block *sb, int verbose) ++{ ++ int i, warned; ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos, *tmp; ++ struct au_icntnr *icntnr; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); ++ ++ /* no spin_lock since sbinfo is write-locked */ ++ warned = 0; ++ for (i = 0; i < AuPlink_NHASH; i++) { ++ hbl = sbinfo->si_plink + i; ++ if (!warned && verbose && !hlist_bl_empty(hbl)) { ++ pr_warn("pseudo-link is not flushed"); ++ warned = 1; ++ } ++ hlist_bl_for_each_entry_safe(icntnr, pos, tmp, hbl, plink) ++ iput(&icntnr->vfs_inode); ++ INIT_HLIST_BL_HEAD(hbl); ++ } ++} ++ ++void au_plink_clean(struct super_block *sb, int verbose) ++{ ++ struct dentry *root; ++ ++ root = sb->s_root; ++ aufs_write_lock(root); ++ if (au_opt_test(au_mntflags(sb), PLINK)) ++ au_plink_put(sb, verbose); ++ aufs_write_unlock(root); ++} ++ ++static int au_plink_do_half_refresh(struct inode *inode, aufs_bindex_t br_id) ++{ ++ int do_put; ++ aufs_bindex_t btop, bbot, bindex; ++ ++ do_put = 0; ++ btop = au_ibtop(inode); ++ bbot = au_ibbot(inode); ++ if (btop >= 0) { ++ for (bindex = btop; bindex <= bbot; bindex++) { ++ if (!au_h_iptr(inode, bindex) ++ || au_ii_br_id(inode, bindex) != br_id) ++ continue; ++ au_set_h_iptr(inode, bindex, NULL, 0); ++ do_put = 1; ++ break; ++ } ++ if (do_put) ++ for (bindex = btop; bindex <= bbot; bindex++) ++ if (au_h_iptr(inode, bindex)) { ++ do_put = 0; ++ break; ++ } ++ } else ++ do_put = 1; ++ ++ return do_put; ++} ++ ++/* free the plinks on a branch specified by @br_id */ ++void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id) ++{ ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos, *tmp; ++ struct au_icntnr *icntnr; ++ struct inode *inode; ++ int i, do_put; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); ++ ++ /* no bit_lock since sbinfo is write-locked */ ++ for (i = 0; i < AuPlink_NHASH; i++) { ++ hbl = sbinfo->si_plink + i; ++ hlist_bl_for_each_entry_safe(icntnr, pos, tmp, hbl, plink) { ++ inode = au_igrab(&icntnr->vfs_inode); ++ ii_write_lock_child(inode); ++ do_put = au_plink_do_half_refresh(inode, br_id); ++ if (do_put) { ++ hlist_bl_del(&icntnr->plink); ++ iput(inode); ++ } ++ ii_write_unlock(inode); ++ iput(inode); ++ } ++ } ++} +diff -Nurp linux-5.15.37/fs/aufs/poll.c linux-5.15.37-aufs/fs/aufs/poll.c +--- linux-5.15.37/fs/aufs/poll.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/poll.c 2022-04-08 20:22:30.615616621 +0300 +@@ -0,0 +1,38 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * poll operation ++ * There is only one filesystem which implements ->poll operation, currently. ++ */ ++ ++#include "aufs.h" ++ ++__poll_t aufs_poll(struct file *file, struct poll_table_struct *pt) ++{ ++ __poll_t mask; ++ struct file *h_file; ++ struct super_block *sb; ++ ++ /* We should pretend an error happened. */ ++ mask = EPOLLERR /* | EPOLLIN | EPOLLOUT */; ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/0, /*lsc*/0); ++ if (IS_ERR(h_file)) { ++ AuDbg("h_file %ld\n", PTR_ERR(h_file)); ++ goto out; ++ } ++ ++ mask = vfs_poll(h_file, pt); ++ fput(h_file); /* instead of au_read_post() */ ++ ++out: ++ si_read_unlock(sb); ++ if (mask & EPOLLERR) ++ AuDbg("mask 0x%x\n", mask); ++ return mask; ++} +diff -Nurp linux-5.15.37/fs/aufs/posix_acl.c linux-5.15.37-aufs/fs/aufs/posix_acl.c +--- linux-5.15.37/fs/aufs/posix_acl.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/posix_acl.c 2022-04-08 20:22:30.615616621 +0300 +@@ -0,0 +1,98 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2014-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * posix acl operations ++ */ ++ ++#include ++#include "aufs.h" ++ ++struct posix_acl *aufs_get_acl(struct inode *inode, int type, bool rcu) ++{ ++ struct posix_acl *acl; ++ int err; ++ aufs_bindex_t bindex; ++ struct inode *h_inode; ++ struct super_block *sb; ++ ++ acl = ERR_PTR(-ECHILD); ++ if (rcu) ++ goto out; ++ ++ acl = NULL; ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ ii_read_lock_child(inode); ++ if (!(sb->s_flags & SB_POSIXACL)) ++ goto unlock; ++ ++ bindex = au_ibtop(inode); ++ h_inode = au_h_iptr(inode, bindex); ++ if (unlikely(!h_inode ++ || ((h_inode->i_mode & S_IFMT) ++ != (inode->i_mode & S_IFMT)))) { ++ err = au_busy_or_stale(); ++ acl = ERR_PTR(err); ++ goto unlock; ++ } ++ ++ /* always topmost only */ ++ acl = get_acl(h_inode, type); ++ if (IS_ERR(acl)) ++ forget_cached_acl(inode, type); ++ else ++ set_cached_acl(inode, type, acl); ++ ++unlock: ++ ii_read_unlock(inode); ++ si_read_unlock(sb); ++ ++out: ++ AuTraceErrPtr(acl); ++ return acl; ++} ++ ++int aufs_set_acl(struct user_namespace *userns, struct inode *inode, ++ struct posix_acl *acl, int type) ++{ ++ int err; ++ ssize_t ssz; ++ struct dentry *dentry; ++ struct au_sxattr arg = { ++ .type = AU_ACL_SET, ++ .u.acl_set = { ++ .acl = acl, ++ .type = type ++ }, ++ }; ++ ++ IMustLock(inode); ++ ++ if (inode->i_ino == AUFS_ROOT_INO) ++ dentry = dget(inode->i_sb->s_root); ++ else { ++ dentry = d_find_alias(inode); ++ if (!dentry) ++ dentry = d_find_any_alias(inode); ++ if (!dentry) { ++ pr_warn("cannot handle this inode, " ++ "please report to aufs-users ML\n"); ++ err = -ENOENT; ++ goto out; ++ } ++ } ++ ++ ssz = au_sxattr(dentry, inode, &arg); ++ /* forget even it if succeeds since the branch might set differently */ ++ forget_cached_acl(inode, type); ++ dput(dentry); ++ err = ssz; ++ if (ssz >= 0) ++ err = 0; ++ ++out: ++ return err; ++} +diff -Nurp linux-5.15.37/fs/aufs/procfs.c linux-5.15.37-aufs/fs/aufs/procfs.c +--- linux-5.15.37/fs/aufs/procfs.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/procfs.c 2022-04-08 20:22:30.615616621 +0300 +@@ -0,0 +1,157 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2010-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * procfs interfaces ++ */ ++ ++#include ++#include "aufs.h" ++ ++static int au_procfs_plm_release(struct inode *inode, struct file *file) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ sbinfo = file->private_data; ++ if (sbinfo) { ++ au_plink_maint_leave(sbinfo); ++ kobject_put(&sbinfo->si_kobj); ++ } ++ ++ return 0; ++} ++ ++static void au_procfs_plm_write_clean(struct file *file) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ sbinfo = file->private_data; ++ if (sbinfo) ++ au_plink_clean(sbinfo->si_sb, /*verbose*/0); ++} ++ ++static int au_procfs_plm_write_si(struct file *file, unsigned long id) ++{ ++ int err; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_node *pos; ++ ++ err = -EBUSY; ++ if (unlikely(file->private_data)) ++ goto out; ++ ++ sb = NULL; ++ /* don't use au_sbilist_lock() here */ ++ hlist_bl_lock(&au_sbilist); ++ hlist_bl_for_each_entry(sbinfo, pos, &au_sbilist, si_list) ++ if (id == sysaufs_si_id(sbinfo)) { ++ if (kobject_get_unless_zero(&sbinfo->si_kobj)) ++ sb = sbinfo->si_sb; ++ break; ++ } ++ hlist_bl_unlock(&au_sbilist); ++ ++ err = -EINVAL; ++ if (unlikely(!sb)) ++ goto out; ++ ++ err = au_plink_maint_enter(sb); ++ if (!err) ++ /* keep kobject_get() */ ++ file->private_data = sbinfo; ++ else ++ kobject_put(&sbinfo->si_kobj); ++out: ++ return err; ++} ++ ++/* ++ * Accept a valid "si=xxxx" only. ++ * Once it is accepted successfully, accept "clean" too. ++ */ ++static ssize_t au_procfs_plm_write(struct file *file, const char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ ssize_t err; ++ unsigned long id; ++ /* last newline is allowed */ ++ char buf[3 + sizeof(unsigned long) * 2 + 1]; ++ ++ err = -EACCES; ++ if (unlikely(!capable(CAP_SYS_ADMIN))) ++ goto out; ++ ++ err = -EINVAL; ++ if (unlikely(count > sizeof(buf))) ++ goto out; ++ ++ err = copy_from_user(buf, ubuf, count); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ goto out; ++ } ++ buf[count] = 0; ++ ++ err = -EINVAL; ++ if (!strcmp("clean", buf)) { ++ au_procfs_plm_write_clean(file); ++ goto out_success; ++ } else if (unlikely(strncmp("si=", buf, 3))) ++ goto out; ++ ++ err = kstrtoul(buf + 3, 16, &id); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_procfs_plm_write_si(file, id); ++ if (unlikely(err)) ++ goto out; ++ ++out_success: ++ err = count; /* success */ ++out: ++ return err; ++} ++ ++static const struct proc_ops au_procfs_plm_op = { ++ .proc_write = au_procfs_plm_write, ++ .proc_release = au_procfs_plm_release ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct proc_dir_entry *au_procfs_dir; ++ ++void au_procfs_fin(void) ++{ ++ remove_proc_entry(AUFS_PLINK_MAINT_NAME, au_procfs_dir); ++ remove_proc_entry(AUFS_PLINK_MAINT_DIR, NULL); ++} ++ ++int __init au_procfs_init(void) ++{ ++ int err; ++ struct proc_dir_entry *entry; ++ ++ err = -ENOMEM; ++ au_procfs_dir = proc_mkdir(AUFS_PLINK_MAINT_DIR, NULL); ++ if (unlikely(!au_procfs_dir)) ++ goto out; ++ ++ entry = proc_create(AUFS_PLINK_MAINT_NAME, S_IFREG | 0200, ++ au_procfs_dir, &au_procfs_plm_op); ++ if (unlikely(!entry)) ++ goto out_dir; ++ ++ err = 0; ++ goto out; /* success */ ++ ++ ++out_dir: ++ remove_proc_entry(AUFS_PLINK_MAINT_DIR, NULL); ++out: ++ return err; ++} +diff -Nurp linux-5.15.37/fs/aufs/rdu.c linux-5.15.37-aufs/fs/aufs/rdu.c +--- linux-5.15.37/fs/aufs/rdu.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/rdu.c 2022-04-08 20:22:30.615616621 +0300 +@@ -0,0 +1,371 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * readdir in userspace. ++ */ ++ ++#include ++#include ++#include ++#include "aufs.h" ++ ++/* bits for struct aufs_rdu.flags */ ++#define AuRdu_CALLED 1 ++#define AuRdu_CONT (1 << 1) ++#define AuRdu_FULL (1 << 2) ++#define au_ftest_rdu(flags, name) ((flags) & AuRdu_##name) ++#define au_fset_rdu(flags, name) \ ++ do { (flags) |= AuRdu_##name; } while (0) ++#define au_fclr_rdu(flags, name) \ ++ do { (flags) &= ~AuRdu_##name; } while (0) ++ ++struct au_rdu_arg { ++ struct dir_context ctx; ++ struct aufs_rdu *rdu; ++ union au_rdu_ent_ul ent; ++ unsigned long end; ++ ++ struct super_block *sb; ++ int err; ++}; ++ ++static int au_rdu_fill(struct dir_context *ctx, const char *name, int nlen, ++ loff_t offset, u64 h_ino, unsigned int d_type) ++{ ++ int err, len; ++ struct au_rdu_arg *arg = container_of(ctx, struct au_rdu_arg, ctx); ++ struct aufs_rdu *rdu = arg->rdu; ++ struct au_rdu_ent ent; ++ ++ err = 0; ++ arg->err = 0; ++ au_fset_rdu(rdu->cookie.flags, CALLED); ++ len = au_rdu_len(nlen); ++ if (arg->ent.ul + len < arg->end) { ++ ent.ino = h_ino; ++ ent.bindex = rdu->cookie.bindex; ++ ent.type = d_type; ++ ent.nlen = nlen; ++ if (unlikely(nlen > AUFS_MAX_NAMELEN)) ++ ent.type = DT_UNKNOWN; ++ ++ /* unnecessary to support mmap_sem since this is a dir */ ++ err = -EFAULT; ++ if (copy_to_user(arg->ent.e, &ent, sizeof(ent))) ++ goto out; ++ if (copy_to_user(arg->ent.e->name, name, nlen)) ++ goto out; ++ /* the terminating NULL */ ++ if (__put_user(0, arg->ent.e->name + nlen)) ++ goto out; ++ err = 0; ++ /* AuDbg("%p, %.*s\n", arg->ent.p, nlen, name); */ ++ arg->ent.ul += len; ++ rdu->rent++; ++ } else { ++ err = -EFAULT; ++ au_fset_rdu(rdu->cookie.flags, FULL); ++ rdu->full = 1; ++ rdu->tail = arg->ent; ++ } ++ ++out: ++ /* AuTraceErr(err); */ ++ return err; ++} ++ ++static int au_rdu_do(struct file *h_file, struct au_rdu_arg *arg) ++{ ++ int err; ++ loff_t offset; ++ struct au_rdu_cookie *cookie = &arg->rdu->cookie; ++ ++ /* we don't have to care (FMODE_32BITHASH | FMODE_64BITHASH) for ext4 */ ++ offset = vfsub_llseek(h_file, cookie->h_pos, SEEK_SET); ++ err = offset; ++ if (unlikely(offset != cookie->h_pos)) ++ goto out; ++ ++ err = 0; ++ do { ++ arg->err = 0; ++ au_fclr_rdu(cookie->flags, CALLED); ++ /* smp_mb(); */ ++ err = vfsub_iterate_dir(h_file, &arg->ctx); ++ if (err >= 0) ++ err = arg->err; ++ } while (!err ++ && au_ftest_rdu(cookie->flags, CALLED) ++ && !au_ftest_rdu(cookie->flags, FULL)); ++ cookie->h_pos = h_file->f_pos; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_rdu(struct file *file, struct aufs_rdu *rdu) ++{ ++ int err; ++ aufs_bindex_t bbot; ++ struct au_rdu_arg arg = { ++ .ctx = { ++ .actor = au_rdu_fill ++ } ++ }; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct file *h_file; ++ struct au_rdu_cookie *cookie = &rdu->cookie; ++ ++ /* VERIFY_WRITE */ ++ err = !access_ok(rdu->ent.e, rdu->sz); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out; ++ } ++ rdu->rent = 0; ++ rdu->tail = rdu->ent; ++ rdu->full = 0; ++ arg.rdu = rdu; ++ arg.ent = rdu->ent; ++ arg.end = arg.ent.ul; ++ arg.end += rdu->sz; ++ ++ err = -ENOTDIR; ++ if (unlikely(!file->f_op->iterate && !file->f_op->iterate_shared)) ++ goto out; ++ ++ err = security_file_permission(file, MAY_READ); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out; ++ ++ dentry = file->f_path.dentry; ++ inode = d_inode(dentry); ++ inode_lock_shared(inode); ++ ++ arg.sb = inode->i_sb; ++ err = si_read_lock(arg.sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out_mtx; ++ err = au_alive_dir(dentry); ++ if (unlikely(err)) ++ goto out_si; ++ /* todo: reval? */ ++ fi_read_lock(file); ++ ++ err = -EAGAIN; ++ if (unlikely(au_ftest_rdu(cookie->flags, CONT) ++ && cookie->generation != au_figen(file))) ++ goto out_unlock; ++ ++ err = 0; ++ if (!rdu->blk) { ++ rdu->blk = au_sbi(arg.sb)->si_rdblk; ++ if (!rdu->blk) ++ rdu->blk = au_dir_size(file, /*dentry*/NULL); ++ } ++ bbot = au_fbtop(file); ++ if (cookie->bindex < bbot) ++ cookie->bindex = bbot; ++ bbot = au_fbbot_dir(file); ++ /* AuDbg("b%d, b%d\n", cookie->bindex, bbot); */ ++ for (; !err && cookie->bindex <= bbot; ++ cookie->bindex++, cookie->h_pos = 0) { ++ h_file = au_hf_dir(file, cookie->bindex); ++ if (!h_file) ++ continue; ++ ++ au_fclr_rdu(cookie->flags, FULL); ++ err = au_rdu_do(h_file, &arg); ++ AuTraceErr(err); ++ if (unlikely(au_ftest_rdu(cookie->flags, FULL) || err)) ++ break; ++ } ++ AuDbg("rent %llu\n", rdu->rent); ++ ++ if (!err && !au_ftest_rdu(cookie->flags, CONT)) { ++ rdu->shwh = !!au_opt_test(au_sbi(arg.sb)->si_mntflags, SHWH); ++ au_fset_rdu(cookie->flags, CONT); ++ cookie->generation = au_figen(file); ++ } ++ ++ ii_read_lock_child(inode); ++ fsstack_copy_attr_atime(inode, au_h_iptr(inode, au_ibtop(inode))); ++ ii_read_unlock(inode); ++ ++out_unlock: ++ fi_read_unlock(file); ++out_si: ++ si_read_unlock(arg.sb); ++out_mtx: ++ inode_unlock_shared(inode); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_rdu_ino(struct file *file, struct aufs_rdu *rdu) ++{ ++ int err; ++ ino_t ino; ++ unsigned long long nent; ++ union au_rdu_ent_ul *u; ++ struct au_rdu_ent ent; ++ struct super_block *sb; ++ ++ err = 0; ++ nent = rdu->nent; ++ u = &rdu->ent; ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ while (nent-- > 0) { ++ /* unnecessary to support mmap_sem since this is a dir */ ++ err = copy_from_user(&ent, u->e, sizeof(ent)); ++ if (!err) ++ /* VERIFY_WRITE */ ++ err = !access_ok(&u->e->ino, sizeof(ino)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ break; ++ } ++ ++ /* AuDbg("b%d, i%llu\n", ent.bindex, ent.ino); */ ++ if (!ent.wh) ++ err = au_ino(sb, ent.bindex, ent.ino, ent.type, &ino); ++ else ++ err = au_wh_ino(sb, ent.bindex, ent.ino, ent.type, ++ &ino); ++ if (unlikely(err)) { ++ AuTraceErr(err); ++ break; ++ } ++ ++ err = __put_user(ino, &u->e->ino); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ break; ++ } ++ u->ul += au_rdu_len(ent.nlen); ++ } ++ si_read_unlock(sb); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_rdu_verify(struct aufs_rdu *rdu) ++{ ++ AuDbg("rdu{%llu, %p, %u | %u | %llu, %u, %u | " ++ "%llu, b%d, 0x%x, g%u}\n", ++ rdu->sz, rdu->ent.e, rdu->verify[AufsCtlRduV_SZ], ++ rdu->blk, ++ rdu->rent, rdu->shwh, rdu->full, ++ rdu->cookie.h_pos, rdu->cookie.bindex, rdu->cookie.flags, ++ rdu->cookie.generation); ++ ++ if (rdu->verify[AufsCtlRduV_SZ] == sizeof(*rdu)) ++ return 0; ++ ++ AuDbg("%u:%u\n", ++ rdu->verify[AufsCtlRduV_SZ], (unsigned int)sizeof(*rdu)); ++ return -EINVAL; ++} ++ ++long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ long err, e; ++ struct aufs_rdu rdu; ++ void __user *p = (void __user *)arg; ++ ++ err = copy_from_user(&rdu, p, sizeof(rdu)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out; ++ } ++ err = au_rdu_verify(&rdu); ++ if (unlikely(err)) ++ goto out; ++ ++ switch (cmd) { ++ case AUFS_CTL_RDU: ++ err = au_rdu(file, &rdu); ++ if (unlikely(err)) ++ break; ++ ++ e = copy_to_user(p, &rdu, sizeof(rdu)); ++ if (unlikely(e)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ } ++ break; ++ case AUFS_CTL_RDU_INO: ++ err = au_rdu_ino(file, &rdu); ++ break; ++ ++ default: ++ /* err = -ENOTTY; */ ++ err = -EINVAL; ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++#ifdef CONFIG_COMPAT ++long au_rdu_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ long err, e; ++ struct aufs_rdu rdu; ++ void __user *p = compat_ptr(arg); ++ ++ /* todo: get_user()? */ ++ err = copy_from_user(&rdu, p, sizeof(rdu)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out; ++ } ++ rdu.ent.e = compat_ptr(rdu.ent.ul); ++ err = au_rdu_verify(&rdu); ++ if (unlikely(err)) ++ goto out; ++ ++ switch (cmd) { ++ case AUFS_CTL_RDU: ++ err = au_rdu(file, &rdu); ++ if (unlikely(err)) ++ break; ++ ++ rdu.ent.ul = ptr_to_compat(rdu.ent.e); ++ rdu.tail.ul = ptr_to_compat(rdu.tail.e); ++ e = copy_to_user(p, &rdu, sizeof(rdu)); ++ if (unlikely(e)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ } ++ break; ++ case AUFS_CTL_RDU_INO: ++ err = au_rdu_ino(file, &rdu); ++ break; ++ ++ default: ++ /* err = -ENOTTY; */ ++ err = -EINVAL; ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++#endif +diff -Nurp linux-5.15.37/fs/aufs/rwsem.h linux-5.15.37-aufs/fs/aufs/rwsem.h +--- linux-5.15.37/fs/aufs/rwsem.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/rwsem.h 2022-04-08 20:22:30.615616621 +0300 +@@ -0,0 +1,72 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * simple read-write semaphore wrappers ++ */ ++ ++#ifndef __AUFS_RWSEM_H__ ++#define __AUFS_RWSEM_H__ ++ ++#ifdef __KERNEL__ ++ ++#include "debug.h" ++ ++/* in the future, the name 'au_rwsem' will be totally gone */ ++#define au_rwsem rw_semaphore ++ ++/* to debug easier, do not make them inlined functions */ ++#define AuRwMustNoWaiters(rw) AuDebugOn(rwsem_is_contended(rw)) ++ ++#ifdef CONFIG_LOCKDEP ++/* rwsem_is_locked() is unusable */ ++#define AuRwMustReadLock(rw) AuDebugOn(IS_ENABLED(CONFIG_LOCKDEP) \ ++ && !lockdep_recursing(current) \ ++ && debug_locks \ ++ && !lockdep_is_held_type(rw, 1)) ++#define AuRwMustWriteLock(rw) AuDebugOn(IS_ENABLED(CONFIG_LOCKDEP) \ ++ && !lockdep_recursing(current) \ ++ && debug_locks \ ++ && !lockdep_is_held_type(rw, 0)) ++#define AuRwMustAnyLock(rw) AuDebugOn(IS_ENABLED(CONFIG_LOCKDEP) \ ++ && !lockdep_recursing(current) \ ++ && debug_locks \ ++ && !lockdep_is_held(rw)) ++#define AuRwDestroy(rw) AuDebugOn(IS_ENABLED(CONFIG_LOCKDEP) \ ++ && !lockdep_recursing(current) \ ++ && debug_locks \ ++ && lockdep_is_held(rw)) ++#else ++#define AuRwMustReadLock(rw) do {} while (0) ++#define AuRwMustWriteLock(rw) do {} while (0) ++#define AuRwMustAnyLock(rw) do {} while (0) ++#define AuRwDestroy(rw) do {} while (0) ++#endif ++ ++#define au_rw_init(rw) init_rwsem(rw) ++ ++#define au_rw_init_wlock(rw) do { \ ++ au_rw_init(rw); \ ++ down_write(rw); \ ++ } while (0) ++ ++#define au_rw_init_wlock_nested(rw, lsc) do { \ ++ au_rw_init(rw); \ ++ down_write_nested(rw, lsc); \ ++ } while (0) ++ ++#define au_rw_read_lock(rw) down_read(rw) ++#define au_rw_read_lock_nested(rw, lsc) down_read_nested(rw, lsc) ++#define au_rw_read_unlock(rw) up_read(rw) ++#define au_rw_dgrade_lock(rw) downgrade_write(rw) ++#define au_rw_write_lock(rw) down_write(rw) ++#define au_rw_write_lock_nested(rw, lsc) down_write_nested(rw, lsc) ++#define au_rw_write_unlock(rw) up_write(rw) ++/* why is not _nested version defined? */ ++#define au_rw_read_trylock(rw) down_read_trylock(rw) ++#define au_rw_write_trylock(rw) down_write_trylock(rw) ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_RWSEM_H__ */ +diff -Nurp linux-5.15.37/fs/aufs/sbinfo.c linux-5.15.37-aufs/fs/aufs/sbinfo.c +--- linux-5.15.37/fs/aufs/sbinfo.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/sbinfo.c 2022-04-08 20:22:30.615616621 +0300 +@@ -0,0 +1,303 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * superblock private data ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* ++ * they are necessary regardless sysfs is disabled. ++ */ ++void au_si_free(struct kobject *kobj) ++{ ++ int i; ++ struct au_sbinfo *sbinfo; ++ char *locked __maybe_unused; /* debug only */ ++ ++ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); ++ for (i = 0; i < AuPlink_NHASH; i++) ++ AuDebugOn(!hlist_bl_empty(sbinfo->si_plink + i)); ++ AuDebugOn(atomic_read(&sbinfo->si_nowait.nw_len)); ++ ++ AuLCntZero(au_lcnt_read(&sbinfo->si_ninodes, /*do_rev*/0)); ++ au_lcnt_fin(&sbinfo->si_ninodes, /*do_sync*/0); ++ AuLCntZero(au_lcnt_read(&sbinfo->si_nfiles, /*do_rev*/0)); ++ au_lcnt_fin(&sbinfo->si_nfiles, /*do_sync*/0); ++ ++ dbgaufs_si_fin(sbinfo); ++ au_rw_write_lock(&sbinfo->si_rwsem); ++ au_br_free(sbinfo); ++ au_rw_write_unlock(&sbinfo->si_rwsem); ++ ++ au_kfree_try_rcu(sbinfo->si_branch); ++ mutex_destroy(&sbinfo->si_xib_mtx); ++ AuRwDestroy(&sbinfo->si_rwsem); ++ ++ au_lcnt_wait_for_fin(&sbinfo->si_ninodes); ++ /* si_nfiles is waited too */ ++ au_kfree_rcu(sbinfo); ++} ++ ++struct au_sbinfo *au_si_alloc(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ int err, i; ++ ++ err = -ENOMEM; ++ sbinfo = kzalloc(sizeof(*sbinfo), GFP_NOFS); ++ if (unlikely(!sbinfo)) ++ goto out; ++ ++ /* will be reallocated separately */ ++ sbinfo->si_branch = kzalloc(sizeof(*sbinfo->si_branch), GFP_NOFS); ++ if (unlikely(!sbinfo->si_branch)) ++ goto out_sbinfo; ++ ++ err = sysaufs_si_init(sbinfo); ++ if (!err) { ++ dbgaufs_si_null(sbinfo); ++ err = dbgaufs_si_init(sbinfo); ++ if (unlikely(err)) ++ kobject_put(&sbinfo->si_kobj); ++ } ++ if (unlikely(err)) ++ goto out_br; ++ ++ au_nwt_init(&sbinfo->si_nowait); ++ au_rw_init_wlock(&sbinfo->si_rwsem); ++ ++ au_lcnt_init(&sbinfo->si_ninodes, /*release*/NULL); ++ au_lcnt_init(&sbinfo->si_nfiles, /*release*/NULL); ++ ++ sbinfo->si_bbot = -1; ++ sbinfo->si_last_br_id = AUFS_BRANCH_MAX / 2; ++ ++ sbinfo->si_wbr_copyup = AuWbrCopyup_Def; ++ sbinfo->si_wbr_create = AuWbrCreate_Def; ++ sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + sbinfo->si_wbr_copyup; ++ sbinfo->si_wbr_create_ops = au_wbr_create_ops + sbinfo->si_wbr_create; ++ ++ au_fhsm_init(sbinfo); ++ ++ sbinfo->si_mntflags = au_opts_plink(AuOpt_Def); ++ ++ sbinfo->si_xino_jiffy = jiffies; ++ sbinfo->si_xino_expire ++ = msecs_to_jiffies(AUFS_XINO_DEF_SEC * MSEC_PER_SEC); ++ mutex_init(&sbinfo->si_xib_mtx); ++ /* leave si_xib_last_pindex and si_xib_next_bit */ ++ ++ INIT_HLIST_BL_HEAD(&sbinfo->si_aopen); ++ ++ sbinfo->si_rdcache = msecs_to_jiffies(AUFS_RDCACHE_DEF * MSEC_PER_SEC); ++ sbinfo->si_rdblk = AUFS_RDBLK_DEF; ++ sbinfo->si_rdhash = AUFS_RDHASH_DEF; ++ sbinfo->si_dirwh = AUFS_DIRWH_DEF; ++ ++ for (i = 0; i < AuPlink_NHASH; i++) ++ INIT_HLIST_BL_HEAD(sbinfo->si_plink + i); ++ init_waitqueue_head(&sbinfo->si_plink_wq); ++ spin_lock_init(&sbinfo->si_plink_maint_lock); ++ ++ INIT_HLIST_BL_HEAD(&sbinfo->si_files); ++ ++ /* with getattr by default */ ++ sbinfo->si_iop_array = aufs_iop; ++ ++ /* leave other members for sysaufs and si_mnt. */ ++ sbinfo->si_sb = sb; ++ if (sb) { ++ sb->s_fs_info = sbinfo; ++ si_pid_set(sb); ++ } ++ return sbinfo; /* success */ ++ ++out_br: ++ au_kfree_try_rcu(sbinfo->si_branch); ++out_sbinfo: ++ au_kfree_rcu(sbinfo); ++out: ++ return ERR_PTR(err); ++} ++ ++int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr, int may_shrink) ++{ ++ int err, sz; ++ struct au_branch **brp; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ err = -ENOMEM; ++ sz = sizeof(*brp) * (sbinfo->si_bbot + 1); ++ if (unlikely(!sz)) ++ sz = sizeof(*brp); ++ brp = au_kzrealloc(sbinfo->si_branch, sz, sizeof(*brp) * nbr, GFP_NOFS, ++ may_shrink); ++ if (brp) { ++ sbinfo->si_branch = brp; ++ err = 0; ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++unsigned int au_sigen_inc(struct super_block *sb) ++{ ++ unsigned int gen; ++ struct inode *inode; ++ ++ SiMustWriteLock(sb); ++ ++ gen = ++au_sbi(sb)->si_generation; ++ au_update_digen(sb->s_root); ++ inode = d_inode(sb->s_root); ++ au_update_iigen(inode, /*half*/0); ++ inode_inc_iversion(inode); ++ return gen; ++} ++ ++aufs_bindex_t au_new_br_id(struct super_block *sb) ++{ ++ aufs_bindex_t br_id; ++ int i; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ for (i = 0; i <= AUFS_BRANCH_MAX; i++) { ++ br_id = ++sbinfo->si_last_br_id; ++ AuDebugOn(br_id < 0); ++ if (br_id && au_br_index(sb, br_id) < 0) ++ return br_id; ++ } ++ ++ return -1; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* it is ok that new 'nwt' tasks are appended while we are sleeping */ ++int si_read_lock(struct super_block *sb, int flags) ++{ ++ int err; ++ ++ err = 0; ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ ++ si_noflush_read_lock(sb); ++ err = au_plink_maint(sb, flags); ++ if (unlikely(err)) ++ si_read_unlock(sb); ++ ++ return err; ++} ++ ++int si_write_lock(struct super_block *sb, int flags) ++{ ++ int err; ++ ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ ++ si_noflush_write_lock(sb); ++ err = au_plink_maint(sb, flags); ++ if (unlikely(err)) ++ si_write_unlock(sb); ++ ++ return err; ++} ++ ++/* dentry and super_block lock. call at entry point */ ++int aufs_read_lock(struct dentry *dentry, int flags) ++{ ++ int err; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ err = si_read_lock(sb, flags); ++ if (unlikely(err)) ++ goto out; ++ ++ if (au_ftest_lock(flags, DW)) ++ di_write_lock_child(dentry); ++ else ++ di_read_lock_child(dentry, flags); ++ ++ if (au_ftest_lock(flags, GEN)) { ++ err = au_digen_test(dentry, au_sigen(sb)); ++ if (!au_opt_test(au_mntflags(sb), UDBA_NONE)) ++ AuDebugOn(!err && au_dbrange_test(dentry)); ++ else if (!err) ++ err = au_dbrange_test(dentry); ++ if (unlikely(err)) ++ aufs_read_unlock(dentry, flags); ++ } ++ ++out: ++ return err; ++} ++ ++void aufs_read_unlock(struct dentry *dentry, int flags) ++{ ++ if (au_ftest_lock(flags, DW)) ++ di_write_unlock(dentry); ++ else ++ di_read_unlock(dentry, flags); ++ si_read_unlock(dentry->d_sb); ++} ++ ++void aufs_write_lock(struct dentry *dentry) ++{ ++ si_write_lock(dentry->d_sb, AuLock_FLUSH | AuLock_NOPLMW); ++ di_write_lock_child(dentry); ++} ++ ++void aufs_write_unlock(struct dentry *dentry) ++{ ++ di_write_unlock(dentry); ++ si_write_unlock(dentry->d_sb); ++} ++ ++int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags) ++{ ++ int err; ++ unsigned int sigen; ++ struct super_block *sb; ++ ++ sb = d1->d_sb; ++ err = si_read_lock(sb, flags); ++ if (unlikely(err)) ++ goto out; ++ ++ di_write_lock2_child(d1, d2, au_ftest_lock(flags, DIRS)); ++ ++ if (au_ftest_lock(flags, GEN)) { ++ sigen = au_sigen(sb); ++ err = au_digen_test(d1, sigen); ++ AuDebugOn(!err && au_dbrange_test(d1)); ++ if (!err) { ++ err = au_digen_test(d2, sigen); ++ AuDebugOn(!err && au_dbrange_test(d2)); ++ } ++ if (unlikely(err)) ++ aufs_read_and_write_unlock2(d1, d2); ++ } ++ ++out: ++ return err; ++} ++ ++void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2) ++{ ++ di_write_unlock2(d1, d2); ++ si_read_unlock(d1->d_sb); ++} +diff -Nurp linux-5.15.37/fs/aufs/super.c linux-5.15.37-aufs/fs/aufs/super.c +--- linux-5.15.37/fs/aufs/super.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/super.c 2022-04-08 20:22:30.615616621 +0300 +@@ -0,0 +1,858 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * mount and super_block operations ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++/* ++ * super_operations ++ */ ++static struct inode *aufs_alloc_inode(struct super_block *sb __maybe_unused) ++{ ++ struct au_icntnr *c; ++ ++ c = au_cache_alloc_icntnr(); ++ if (c) { ++ au_icntnr_init(c); ++ inode_set_iversion(&c->vfs_inode, 1); /* sigen(sb); */ ++ c->iinfo.ii_hinode = NULL; ++ return &c->vfs_inode; ++ } ++ return NULL; ++} ++ ++static void aufs_destroy_inode(struct inode *inode) ++{ ++ if (!au_is_bad_inode(inode)) ++ au_iinfo_fin(inode); ++} ++ ++static void aufs_free_inode(struct inode *inode) ++{ ++ au_cache_free_icntnr(container_of(inode, struct au_icntnr, vfs_inode)); ++} ++ ++struct inode *au_iget_locked(struct super_block *sb, ino_t ino) ++{ ++ struct inode *inode; ++ int err; ++ ++ inode = iget_locked(sb, ino); ++ if (unlikely(!inode)) { ++ inode = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ if (!(inode->i_state & I_NEW)) ++ goto out; ++ ++ err = au_xigen_new(inode); ++ if (!err) ++ err = au_iinfo_init(inode); ++ if (!err) ++ inode_inc_iversion(inode); ++ else { ++ iget_failed(inode); ++ inode = ERR_PTR(err); ++ } ++ ++out: ++ /* never return NULL */ ++ AuDebugOn(!inode); ++ AuTraceErrPtr(inode); ++ return inode; ++} ++ ++/* lock free root dinfo */ ++static int au_show_brs(struct seq_file *seq, struct super_block *sb) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct path path; ++ struct au_hdentry *hdp; ++ struct au_branch *br; ++ au_br_perm_str_t perm; ++ ++ err = 0; ++ bbot = au_sbbot(sb); ++ bindex = 0; ++ hdp = au_hdentry(au_di(sb->s_root), bindex); ++ for (; !err && bindex <= bbot; bindex++, hdp++) { ++ br = au_sbr(sb, bindex); ++ path.mnt = au_br_mnt(br); ++ path.dentry = hdp->hd_dentry; ++ err = au_seq_path(seq, &path); ++ if (!err) { ++ au_optstr_br_perm(&perm, br->br_perm); ++ seq_printf(seq, "=%s", perm.a); ++ if (bindex != bbot) ++ seq_putc(seq, ':'); ++ } ++ } ++ if (unlikely(err || seq_has_overflowed(seq))) ++ err = -E2BIG; ++ ++ return err; ++} ++ ++static void au_gen_fmt(char *fmt, int len __maybe_unused, const char *pat, ++ const char *append) ++{ ++ char *p; ++ ++ p = fmt; ++ while (*pat != ':') ++ *p++ = *pat++; ++ *p++ = *pat++; ++ strcpy(p, append); ++ AuDebugOn(strlen(fmt) >= len); ++} ++ ++static void au_show_wbr_create(struct seq_file *m, int v, ++ struct au_sbinfo *sbinfo) ++{ ++ const char *pat; ++ char fmt[32]; ++ struct au_wbr_mfs *mfs; ++ ++ AuRwMustAnyLock(&sbinfo->si_rwsem); ++ ++ seq_puts(m, ",create="); ++ pat = au_optstr_wbr_create(v); ++ mfs = &sbinfo->si_wbr_mfs; ++ switch (v) { ++ case AuWbrCreate_TDP: ++ case AuWbrCreate_RR: ++ case AuWbrCreate_MFS: ++ case AuWbrCreate_PMFS: ++ seq_puts(m, pat); ++ break; ++ case AuWbrCreate_MFSRR: ++ case AuWbrCreate_TDMFS: ++ case AuWbrCreate_PMFSRR: ++ au_gen_fmt(fmt, sizeof(fmt), pat, "%llu"); ++ seq_printf(m, fmt, mfs->mfsrr_watermark); ++ break; ++ case AuWbrCreate_MFSV: ++ case AuWbrCreate_PMFSV: ++ au_gen_fmt(fmt, sizeof(fmt), pat, "%lu"); ++ seq_printf(m, fmt, ++ jiffies_to_msecs(mfs->mfs_expire) ++ / MSEC_PER_SEC); ++ break; ++ case AuWbrCreate_MFSRRV: ++ case AuWbrCreate_TDMFSV: ++ case AuWbrCreate_PMFSRRV: ++ au_gen_fmt(fmt, sizeof(fmt), pat, "%llu:%lu"); ++ seq_printf(m, fmt, mfs->mfsrr_watermark, ++ jiffies_to_msecs(mfs->mfs_expire) / MSEC_PER_SEC); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++static int au_show_xino(struct seq_file *seq, struct super_block *sb) ++{ ++#ifdef CONFIG_SYSFS ++ return 0; ++#else ++ int err; ++ const int len = sizeof(AUFS_XINO_FNAME) - 1; ++ aufs_bindex_t bindex, brid; ++ struct qstr *name; ++ struct file *f; ++ struct dentry *d, *h_root; ++ struct au_branch *br; ++ ++ AuRwMustAnyLock(&sbinfo->si_rwsem); ++ ++ err = 0; ++ f = au_sbi(sb)->si_xib; ++ if (!f) ++ goto out; ++ ++ /* stop printing the default xino path on the first writable branch */ ++ h_root = NULL; ++ bindex = au_xi_root(sb, f->f_path.dentry); ++ if (bindex >= 0) { ++ br = au_sbr_sb(sb, bindex); ++ h_root = au_br_dentry(br); ++ } ++ ++ d = f->f_path.dentry; ++ name = &d->d_name; ++ /* safe ->d_parent because the file is unlinked */ ++ if (d->d_parent == h_root ++ && name->len == len ++ && !memcmp(name->name, AUFS_XINO_FNAME, len)) ++ goto out; ++ ++ seq_puts(seq, ",xino="); ++ err = au_xino_path(seq, f); ++ ++out: ++ return err; ++#endif ++} ++ ++/* seq_file will re-call me in case of too long string */ ++static int aufs_show_options(struct seq_file *m, struct dentry *dentry) ++{ ++ int err; ++ unsigned int mnt_flags, v; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ ++#define AuBool(name, str) do { \ ++ v = au_opt_test(mnt_flags, name); \ ++ if (v != au_opt_test(AuOpt_Def, name)) \ ++ seq_printf(m, ",%s" #str, v ? "" : "no"); \ ++} while (0) ++ ++#define AuStr(name, str) do { \ ++ v = mnt_flags & AuOptMask_##name; \ ++ if (v != (AuOpt_Def & AuOptMask_##name)) \ ++ seq_printf(m, "," #str "=%s", au_optstr_##str(v)); \ ++} while (0) ++ ++#define AuUInt(name, str, val) do { \ ++ if (val != AUFS_##name##_DEF) \ ++ seq_printf(m, "," #str "=%u", val); \ ++} while (0) ++ ++ sb = dentry->d_sb; ++ if (sb->s_flags & SB_POSIXACL) ++ seq_puts(m, ",acl"); ++#if 0 /* reserved for future use */ ++ if (sb->s_flags & SB_I_VERSION) ++ seq_puts(m, ",i_version"); ++#endif ++ ++ /* lock free root dinfo */ ++ si_noflush_read_lock(sb); ++ sbinfo = au_sbi(sb); ++ seq_printf(m, ",si=%lx", sysaufs_si_id(sbinfo)); ++ ++ mnt_flags = au_mntflags(sb); ++ if (au_opt_test(mnt_flags, XINO)) { ++ err = au_show_xino(m, sb); ++ if (unlikely(err)) ++ goto out; ++ } else ++ seq_puts(m, ",noxino"); ++ ++ AuBool(TRUNC_XINO, trunc_xino); ++ AuStr(UDBA, udba); ++ AuBool(SHWH, shwh); ++ AuBool(PLINK, plink); ++ AuBool(DIO, dio); ++ AuBool(DIRPERM1, dirperm1); ++ ++ v = sbinfo->si_wbr_create; ++ if (v != AuWbrCreate_Def) ++ au_show_wbr_create(m, v, sbinfo); ++ ++ v = sbinfo->si_wbr_copyup; ++ if (v != AuWbrCopyup_Def) ++ seq_printf(m, ",cpup=%s", au_optstr_wbr_copyup(v)); ++ ++ v = au_opt_test(mnt_flags, ALWAYS_DIROPQ); ++ if (v != au_opt_test(AuOpt_Def, ALWAYS_DIROPQ)) ++ seq_printf(m, ",diropq=%c", v ? 'a' : 'w'); ++ ++ AuUInt(DIRWH, dirwh, sbinfo->si_dirwh); ++ ++ v = jiffies_to_msecs(sbinfo->si_rdcache) / MSEC_PER_SEC; ++ AuUInt(RDCACHE, rdcache, v); ++ ++ AuUInt(RDBLK, rdblk, sbinfo->si_rdblk); ++ AuUInt(RDHASH, rdhash, sbinfo->si_rdhash); ++ ++ au_fhsm_show(m, sbinfo); ++ ++ AuBool(DIRREN, dirren); ++ AuBool(SUM, sum); ++ /* AuBool(SUM_W, wsum); */ ++ AuBool(WARN_PERM, warn_perm); ++ AuBool(VERBOSE, verbose); ++ ++out: ++ /* be sure to print "br:" last */ ++ if (!sysaufs_brs) { ++ seq_puts(m, ",br:"); ++ au_show_brs(m, sb); ++ } ++ si_read_unlock(sb); ++ return 0; ++ ++#undef AuBool ++#undef AuStr ++#undef AuUInt ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* sum mode which returns the summation for statfs(2) */ ++ ++static u64 au_add_till_max(u64 a, u64 b) ++{ ++ u64 old; ++ ++ old = a; ++ a += b; ++ if (old <= a) ++ return a; ++ return ULLONG_MAX; ++} ++ ++static u64 au_mul_till_max(u64 a, long mul) ++{ ++ u64 old; ++ ++ old = a; ++ a *= mul; ++ if (old <= a) ++ return a; ++ return ULLONG_MAX; ++} ++ ++static int au_statfs_sum(struct super_block *sb, struct kstatfs *buf) ++{ ++ int err; ++ long bsize, factor; ++ u64 blocks, bfree, bavail, files, ffree; ++ aufs_bindex_t bbot, bindex, i; ++ unsigned char shared; ++ struct path h_path; ++ struct super_block *h_sb; ++ ++ err = 0; ++ bsize = LONG_MAX; ++ files = 0; ++ ffree = 0; ++ blocks = 0; ++ bfree = 0; ++ bavail = 0; ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ h_path.mnt = au_sbr_mnt(sb, bindex); ++ h_sb = h_path.mnt->mnt_sb; ++ shared = 0; ++ for (i = 0; !shared && i < bindex; i++) ++ shared = (au_sbr_sb(sb, i) == h_sb); ++ if (shared) ++ continue; ++ ++ /* sb->s_root for NFS is unreliable */ ++ h_path.dentry = h_path.mnt->mnt_root; ++ err = vfs_statfs(&h_path, buf); ++ if (unlikely(err)) ++ goto out; ++ ++ if (bsize > buf->f_bsize) { ++ /* ++ * we will reduce bsize, so we have to expand blocks ++ * etc. to match them again ++ */ ++ factor = (bsize / buf->f_bsize); ++ blocks = au_mul_till_max(blocks, factor); ++ bfree = au_mul_till_max(bfree, factor); ++ bavail = au_mul_till_max(bavail, factor); ++ bsize = buf->f_bsize; ++ } ++ ++ factor = (buf->f_bsize / bsize); ++ blocks = au_add_till_max(blocks, ++ au_mul_till_max(buf->f_blocks, factor)); ++ bfree = au_add_till_max(bfree, ++ au_mul_till_max(buf->f_bfree, factor)); ++ bavail = au_add_till_max(bavail, ++ au_mul_till_max(buf->f_bavail, factor)); ++ files = au_add_till_max(files, buf->f_files); ++ ffree = au_add_till_max(ffree, buf->f_ffree); ++ } ++ ++ buf->f_bsize = bsize; ++ buf->f_blocks = blocks; ++ buf->f_bfree = bfree; ++ buf->f_bavail = bavail; ++ buf->f_files = files; ++ buf->f_ffree = ffree; ++ buf->f_frsize = 0; ++ ++out: ++ return err; ++} ++ ++static int aufs_statfs(struct dentry *dentry, struct kstatfs *buf) ++{ ++ int err; ++ struct path h_path; ++ struct super_block *sb; ++ ++ /* lock free root dinfo */ ++ sb = dentry->d_sb; ++ si_noflush_read_lock(sb); ++ if (!au_opt_test(au_mntflags(sb), SUM)) { ++ /* sb->s_root for NFS is unreliable */ ++ h_path.mnt = au_sbr_mnt(sb, 0); ++ h_path.dentry = h_path.mnt->mnt_root; ++ err = vfs_statfs(&h_path, buf); ++ } else ++ err = au_statfs_sum(sb, buf); ++ si_read_unlock(sb); ++ ++ if (!err) { ++ buf->f_type = AUFS_SUPER_MAGIC; ++ buf->f_namelen = AUFS_MAX_NAMELEN; ++ memset(&buf->f_fsid, 0, sizeof(buf->f_fsid)); ++ } ++ /* buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1; */ ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_sync_fs(struct super_block *sb, int wait) ++{ ++ int err, e; ++ aufs_bindex_t bbot, bindex; ++ struct au_branch *br; ++ struct super_block *h_sb; ++ ++ err = 0; ++ si_noflush_read_lock(sb); ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!au_br_writable(br->br_perm)) ++ continue; ++ ++ h_sb = au_sbr_sb(sb, bindex); ++ e = vfsub_sync_filesystem(h_sb); ++ if (unlikely(e && !err)) ++ err = e; ++ /* go on even if an error happens */ ++ } ++ si_read_unlock(sb); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* final actions when unmounting a file system */ ++static void aufs_put_super(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ sbinfo = au_sbi(sb); ++ if (sbinfo) ++ kobject_put(&sbinfo->si_kobj); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, ++ struct super_block *sb, void *arg) ++{ ++ void *array; ++ unsigned long long n, sz; ++ ++ array = NULL; ++ n = 0; ++ if (!*hint) ++ goto out; ++ ++ if (*hint > ULLONG_MAX / sizeof(array)) { ++ array = ERR_PTR(-EMFILE); ++ pr_err("hint %llu\n", *hint); ++ goto out; ++ } ++ ++ sz = sizeof(array) * *hint; ++ array = kzalloc(sz, GFP_NOFS); ++ if (unlikely(!array)) ++ array = vzalloc(sz); ++ if (unlikely(!array)) { ++ array = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ ++ n = cb(sb, array, *hint, arg); ++ AuDebugOn(n > *hint); ++ ++out: ++ *hint = n; ++ return array; ++} ++ ++static unsigned long long au_iarray_cb(struct super_block *sb, void *a, ++ unsigned long long max __maybe_unused, ++ void *arg) ++{ ++ unsigned long long n; ++ struct inode **p, *inode; ++ struct list_head *head; ++ ++ n = 0; ++ p = a; ++ head = arg; ++ spin_lock(&sb->s_inode_list_lock); ++ list_for_each_entry(inode, head, i_sb_list) { ++ if (!au_is_bad_inode(inode) ++ && au_ii(inode)->ii_btop >= 0) { ++ spin_lock(&inode->i_lock); ++ if (atomic_read(&inode->i_count)) { ++ au_igrab(inode); ++ *p++ = inode; ++ n++; ++ AuDebugOn(n > max); ++ } ++ spin_unlock(&inode->i_lock); ++ } ++ } ++ spin_unlock(&sb->s_inode_list_lock); ++ ++ return n; ++} ++ ++struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max) ++{ ++ struct au_sbinfo *sbi; ++ ++ sbi = au_sbi(sb); ++ *max = au_lcnt_read(&sbi->si_ninodes, /*do_rev*/1); ++ return au_array_alloc(max, au_iarray_cb, sb, &sb->s_inodes); ++} ++ ++void au_iarray_free(struct inode **a, unsigned long long max) ++{ ++ unsigned long long ull; ++ ++ for (ull = 0; ull < max; ull++) ++ iput(a[ull]); ++ kvfree(a); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * refresh dentry and inode at remount time. ++ */ ++/* todo: consolidate with simple_reval_dpath() and au_reval_for_attr() */ ++static int au_do_refresh(struct dentry *dentry, unsigned int dir_flags, ++ struct dentry *parent) ++{ ++ int err; ++ ++ di_write_lock_child(dentry); ++ di_read_lock_parent(parent, AuLock_IR); ++ err = au_refresh_dentry(dentry, parent); ++ if (!err && dir_flags) ++ au_hn_reset(d_inode(dentry), dir_flags); ++ di_read_unlock(parent, AuLock_IR); ++ di_write_unlock(dentry); ++ ++ return err; ++} ++ ++static int au_do_refresh_d(struct dentry *dentry, unsigned int sigen, ++ struct au_sbinfo *sbinfo, ++ const unsigned int dir_flags, unsigned int do_idop) ++{ ++ int err; ++ struct dentry *parent; ++ ++ err = 0; ++ parent = dget_parent(dentry); ++ if (!au_digen_test(parent, sigen) && au_digen_test(dentry, sigen)) { ++ if (d_really_is_positive(dentry)) { ++ if (!d_is_dir(dentry)) ++ err = au_do_refresh(dentry, /*dir_flags*/0, ++ parent); ++ else { ++ err = au_do_refresh(dentry, dir_flags, parent); ++ if (unlikely(err)) ++ au_fset_si(sbinfo, FAILED_REFRESH_DIR); ++ } ++ } else ++ err = au_do_refresh(dentry, /*dir_flags*/0, parent); ++ AuDbgDentry(dentry); ++ } ++ dput(parent); ++ ++ if (!err) { ++ if (do_idop) ++ au_refresh_dop(dentry, /*force_reval*/0); ++ } else ++ au_refresh_dop(dentry, /*force_reval*/1); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_refresh_d(struct super_block *sb, unsigned int do_idop) ++{ ++ int err, i, j, ndentry, e; ++ unsigned int sigen; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries, *d; ++ struct au_sbinfo *sbinfo; ++ struct dentry *root = sb->s_root; ++ const unsigned int dir_flags = au_hi_flags(d_inode(root), /*isdir*/1); ++ ++ if (do_idop) ++ au_refresh_dop(root, /*force_reval*/0); ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, root, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ sigen = au_sigen(sb); ++ sbinfo = au_sbi(sb); ++ for (i = 0; i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ ndentry = dpage->ndentry; ++ for (j = 0; j < ndentry; j++) { ++ d = dentries[j]; ++ e = au_do_refresh_d(d, sigen, sbinfo, dir_flags, ++ do_idop); ++ if (unlikely(e && !err)) ++ err = e; ++ /* go on even err */ ++ } ++ } ++ ++out_dpages: ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++static int au_refresh_i(struct super_block *sb, unsigned int do_idop) ++{ ++ int err, e; ++ unsigned int sigen; ++ unsigned long long max, ull; ++ struct inode *inode, **array; ++ ++ array = au_iarray_alloc(sb, &max); ++ err = PTR_ERR(array); ++ if (IS_ERR(array)) ++ goto out; ++ ++ err = 0; ++ sigen = au_sigen(sb); ++ for (ull = 0; ull < max; ull++) { ++ inode = array[ull]; ++ if (unlikely(!inode)) ++ break; ++ ++ e = 0; ++ ii_write_lock_child(inode); ++ if (au_iigen(inode, NULL) != sigen) { ++ e = au_refresh_hinode_self(inode); ++ if (unlikely(e)) { ++ au_refresh_iop(inode, /*force_getattr*/1); ++ pr_err("error %d, i%lu\n", e, inode->i_ino); ++ if (!err) ++ err = e; ++ /* go on even if err */ ++ } ++ } ++ if (!e && do_idop) ++ au_refresh_iop(inode, /*force_getattr*/0); ++ ii_write_unlock(inode); ++ } ++ ++ au_iarray_free(array, max); ++ ++out: ++ return err; ++} ++ ++void au_remount_refresh(struct super_block *sb, unsigned int do_idop) ++{ ++ int err, e; ++ unsigned int udba; ++ aufs_bindex_t bindex, bbot; ++ struct dentry *root; ++ struct inode *inode; ++ struct au_branch *br; ++ struct au_sbinfo *sbi; ++ ++ au_sigen_inc(sb); ++ sbi = au_sbi(sb); ++ au_fclr_si(sbi, FAILED_REFRESH_DIR); ++ ++ root = sb->s_root; ++ DiMustNoWaiters(root); ++ inode = d_inode(root); ++ IiMustNoWaiters(inode); ++ ++ udba = au_opt_udba(sb); ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ err = au_hnotify_reset_br(udba, br, br->br_perm); ++ if (unlikely(err)) ++ AuIOErr("hnotify failed on br %d, %d, ignored\n", ++ bindex, err); ++ /* go on even if err */ ++ } ++ au_hn_reset(inode, au_hi_flags(inode, /*isdir*/1)); ++ ++ if (do_idop) { ++ if (au_ftest_si(sbi, NO_DREVAL)) { ++ AuDebugOn(sb->s_d_op == &aufs_dop_noreval); ++ sb->s_d_op = &aufs_dop_noreval; ++ AuDebugOn(sbi->si_iop_array == aufs_iop_nogetattr); ++ sbi->si_iop_array = aufs_iop_nogetattr; ++ } else { ++ AuDebugOn(sb->s_d_op == &aufs_dop); ++ sb->s_d_op = &aufs_dop; ++ AuDebugOn(sbi->si_iop_array == aufs_iop); ++ sbi->si_iop_array = aufs_iop; ++ } ++ pr_info("reset to %ps and %ps\n", ++ sb->s_d_op, sbi->si_iop_array); ++ } ++ ++ di_write_unlock(root); ++ err = au_refresh_d(sb, do_idop); ++ e = au_refresh_i(sb, do_idop); ++ if (unlikely(e && !err)) ++ err = e; ++ /* aufs_write_lock() calls ..._child() */ ++ di_write_lock_child(root); ++ ++ au_cpup_attr_all(inode, /*force*/1); ++ ++ if (unlikely(err)) ++ AuIOErr("refresh failed, ignored, %d\n", err); ++} ++ ++const struct super_operations aufs_sop = { ++ .alloc_inode = aufs_alloc_inode, ++ .destroy_inode = aufs_destroy_inode, ++ .free_inode = aufs_free_inode, ++ /* always deleting, no clearing */ ++ .drop_inode = generic_delete_inode, ++ .show_options = aufs_show_options, ++ .statfs = aufs_statfs, ++ .put_super = aufs_put_super, ++ .sync_fs = aufs_sync_fs ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_alloc_root(struct super_block *sb) ++{ ++ int err; ++ struct inode *inode; ++ struct dentry *root; ++ ++ err = -ENOMEM; ++ inode = au_iget_locked(sb, AUFS_ROOT_INO); ++ err = PTR_ERR(inode); ++ if (IS_ERR(inode)) ++ goto out; ++ ++ inode->i_op = aufs_iop + AuIop_DIR; /* with getattr by default */ ++ inode->i_fop = &aufs_dir_fop; ++ inode->i_mode = S_IFDIR; ++ set_nlink(inode, 2); ++ unlock_new_inode(inode); ++ ++ root = d_make_root(inode); ++ if (unlikely(!root)) ++ goto out; ++ err = PTR_ERR(root); ++ if (IS_ERR(root)) ++ goto out; ++ ++ err = au_di_init(root); ++ if (!err) { ++ sb->s_root = root; ++ return 0; /* success */ ++ } ++ dput(root); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void aufs_kill_sb(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ struct dentry *root; ++ ++ sbinfo = au_sbi(sb); ++ if (!sbinfo) ++ goto out; ++ ++ au_sbilist_del(sb); ++ ++ root = sb->s_root; ++ if (root) ++ aufs_write_lock(root); ++ else ++ __si_write_lock(sb); ++ ++ au_fhsm_fin(sb); ++ if (sbinfo->si_wbr_create_ops->fin) ++ sbinfo->si_wbr_create_ops->fin(sb); ++ if (au_opt_test(sbinfo->si_mntflags, UDBA_HNOTIFY)) { ++ au_opt_set_udba(sbinfo->si_mntflags, UDBA_NONE); ++ au_remount_refresh(sb, /*do_idop*/0); ++ } ++ if (au_opt_test(sbinfo->si_mntflags, PLINK)) ++ au_plink_put(sb, /*verbose*/1); ++ au_xino_clr(sb); ++ if (root) ++ au_dr_opt_flush(sb); ++ ++ if (root) ++ aufs_write_unlock(root); ++ else ++ __si_write_unlock(sb); ++ ++ sbinfo->si_sb = NULL; ++ au_nwt_flush(&sbinfo->si_nowait); ++ ++out: ++ kill_anon_super(sb); ++} ++ ++struct file_system_type aufs_fs_type = { ++ .name = AUFS_FSTYPE, ++ /* a race between rename and others */ ++ .fs_flags = FS_RENAME_DOES_D_MOVE ++ /* untested */ ++ /*| FS_ALLOW_IDMAP*/ ++ , ++ .init_fs_context = aufs_fsctx_init, ++ .parameters = aufs_fsctx_paramspec, ++ .kill_sb = aufs_kill_sb, ++ /* no need to __module_get() and module_put(). */ ++ .owner = THIS_MODULE, ++}; +diff -Nurp linux-5.15.37/fs/aufs/super.h linux-5.15.37-aufs/fs/aufs/super.h +--- linux-5.15.37/fs/aufs/super.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/super.h 2022-04-08 20:22:30.615616621 +0300 +@@ -0,0 +1,579 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * super_block operations ++ */ ++ ++#ifndef __AUFS_SUPER_H__ ++#define __AUFS_SUPER_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include "hbl.h" ++#include "lcnt.h" ++#include "rwsem.h" ++#include "wkq.h" ++ ++/* policies to select one among multiple writable branches */ ++struct au_wbr_copyup_operations { ++ int (*copyup)(struct dentry *dentry); ++}; ++ ++#define AuWbr_DIR 1 /* target is a dir */ ++#define AuWbr_PARENT (1 << 1) /* always require a parent */ ++ ++#define au_ftest_wbr(flags, name) ((flags) & AuWbr_##name) ++#define au_fset_wbr(flags, name) { (flags) |= AuWbr_##name; } ++#define au_fclr_wbr(flags, name) { (flags) &= ~AuWbr_##name; } ++ ++struct au_wbr_create_operations { ++ int (*create)(struct dentry *dentry, unsigned int flags); ++ int (*init)(struct super_block *sb); ++ int (*fin)(struct super_block *sb); ++}; ++ ++struct au_wbr_mfs { ++ struct mutex mfs_lock; /* protect this structure */ ++ unsigned long mfs_jiffy; ++ unsigned long mfs_expire; ++ aufs_bindex_t mfs_bindex; ++ ++ unsigned long long mfsrr_bytes; ++ unsigned long long mfsrr_watermark; ++}; ++ ++#define AuPlink_NHASH 100 ++static inline int au_plink_hash(ino_t ino) ++{ ++ return ino % AuPlink_NHASH; ++} ++ ++/* File-based Hierarchical Storage Management */ ++struct au_fhsm { ++#ifdef CONFIG_AUFS_FHSM ++ /* allow only one process who can receive the notification */ ++ spinlock_t fhsm_spin; ++ pid_t fhsm_pid; ++ wait_queue_head_t fhsm_wqh; ++ atomic_t fhsm_readable; ++ ++ /* these are protected by si_rwsem */ ++ unsigned long fhsm_expire; ++ aufs_bindex_t fhsm_bottom; ++#endif ++}; ++ ++struct au_branch; ++struct au_sbinfo { ++ /* nowait tasks in the system-wide workqueue */ ++ struct au_nowait_tasks si_nowait; ++ ++ /* ++ * tried sb->s_umount, but failed due to the dependency between i_mutex. ++ * rwsem for au_sbinfo is necessary. ++ */ ++ struct au_rwsem si_rwsem; ++ ++ /* ++ * dirty approach to protect sb->sb_inodes and ->s_files (gone) from ++ * remount. ++ */ ++ au_lcnt_t si_ninodes, si_nfiles; ++ ++ /* branch management */ ++ unsigned int si_generation; ++ ++ /* see AuSi_ flags */ ++ unsigned char au_si_status; ++ ++ aufs_bindex_t si_bbot; ++ ++ /* dirty trick to keep br_id plus */ ++ unsigned int si_last_br_id : ++ sizeof(aufs_bindex_t) * BITS_PER_BYTE - 1; ++ struct au_branch **si_branch; ++ ++ /* policy to select a writable branch */ ++ unsigned char si_wbr_copyup; ++ unsigned char si_wbr_create; ++ struct au_wbr_copyup_operations *si_wbr_copyup_ops; ++ struct au_wbr_create_operations *si_wbr_create_ops; ++ ++ /* round robin */ ++ atomic_t si_wbr_rr_next; ++ ++ /* most free space */ ++ struct au_wbr_mfs si_wbr_mfs; ++ ++ /* File-based Hierarchical Storage Management */ ++ struct au_fhsm si_fhsm; ++ ++ /* mount flags */ ++ /* include/asm-ia64/siginfo.h defines a macro named si_flags */ ++ unsigned int si_mntflags; ++ ++ /* external inode number (bitmap and translation table) */ ++ loff_t si_ximaxent; /* max entries in a xino */ ++ ++ struct file *si_xib; ++ struct mutex si_xib_mtx; /* protect xib members */ ++ unsigned long *si_xib_buf; ++ unsigned long si_xib_last_pindex; ++ int si_xib_next_bit; ++ ++ unsigned long si_xino_jiffy; ++ unsigned long si_xino_expire; ++ /* reserved for future use */ ++ /* unsigned long long si_xib_limit; */ /* Max xib file size */ ++ ++#ifdef CONFIG_AUFS_EXPORT ++ /* i_generation */ ++ /* todo: make xigen file an array to support many inode numbers */ ++ struct file *si_xigen; ++ atomic_t si_xigen_next; ++#endif ++ ++ /* dirty trick to support atomic_open */ ++ struct hlist_bl_head si_aopen; ++ ++ /* vdir parameters */ ++ unsigned long si_rdcache; /* max cache time in jiffies */ ++ unsigned int si_rdblk; /* deblk size */ ++ unsigned int si_rdhash; /* hash size */ ++ ++ /* ++ * If the number of whiteouts are larger than si_dirwh, leave all of ++ * them after au_whtmp_ren to reduce the cost of rmdir(2). ++ * future fsck.aufs or kernel thread will remove them later. ++ * Otherwise, remove all whiteouts and the dir in rmdir(2). ++ */ ++ unsigned int si_dirwh; ++ ++ /* pseudo_link list */ ++ struct hlist_bl_head si_plink[AuPlink_NHASH]; ++ wait_queue_head_t si_plink_wq; ++ spinlock_t si_plink_maint_lock; ++ pid_t si_plink_maint_pid; ++ ++ /* file list */ ++ struct hlist_bl_head si_files; ++ ++ /* with/without getattr, brother of sb->s_d_op */ ++ const struct inode_operations *si_iop_array; ++ ++ /* ++ * sysfs and lifetime management. ++ * this is not a small structure and it may be a waste of memory in case ++ * of sysfs is disabled, particularly when many aufs-es are mounted. ++ * but using sysfs is majority. ++ */ ++ struct kobject si_kobj; ++#ifdef CONFIG_DEBUG_FS ++ struct dentry *si_dbgaufs; ++ struct dentry *si_dbgaufs_plink; ++ struct dentry *si_dbgaufs_xib; ++#ifdef CONFIG_AUFS_EXPORT ++ struct dentry *si_dbgaufs_xigen; ++#endif ++#endif ++ ++#ifdef CONFIG_AUFS_SBILIST ++ struct hlist_bl_node si_list; ++#endif ++ ++ /* dirty, necessary for unmounting, sysfs and sysrq */ ++ struct super_block *si_sb; ++}; ++ ++/* sbinfo status flags */ ++/* ++ * set true when refresh_dirs() failed at remount time. ++ * then try refreshing dirs at access time again. ++ * if it is false, refreshing dirs at access time is unnecessary ++ */ ++#define AuSi_FAILED_REFRESH_DIR 1 ++#define AuSi_FHSM (1 << 1) /* fhsm is active now */ ++#define AuSi_NO_DREVAL (1 << 2) /* disable all d_revalidate */ ++ ++#ifndef CONFIG_AUFS_FHSM ++#undef AuSi_FHSM ++#define AuSi_FHSM 0 ++#endif ++ ++static inline unsigned char au_do_ftest_si(struct au_sbinfo *sbi, ++ unsigned int flag) ++{ ++ AuRwMustAnyLock(&sbi->si_rwsem); ++ return sbi->au_si_status & flag; ++} ++#define au_ftest_si(sbinfo, name) au_do_ftest_si(sbinfo, AuSi_##name) ++#define au_fset_si(sbinfo, name) do { \ ++ AuRwMustWriteLock(&(sbinfo)->si_rwsem); \ ++ (sbinfo)->au_si_status |= AuSi_##name; \ ++} while (0) ++#define au_fclr_si(sbinfo, name) do { \ ++ AuRwMustWriteLock(&(sbinfo)->si_rwsem); \ ++ (sbinfo)->au_si_status &= ~AuSi_##name; \ ++} while (0) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policy to select one among writable branches */ ++#define AuWbrCopyup(sbinfo, ...) \ ++ ((sbinfo)->si_wbr_copyup_ops->copyup(__VA_ARGS__)) ++#define AuWbrCreate(sbinfo, ...) \ ++ ((sbinfo)->si_wbr_create_ops->create(__VA_ARGS__)) ++ ++/* flags for si_read_lock()/aufs_read_lock()/di_read_lock() */ ++#define AuLock_DW 1 /* write-lock dentry */ ++#define AuLock_IR (1 << 1) /* read-lock inode */ ++#define AuLock_IW (1 << 2) /* write-lock inode */ ++#define AuLock_FLUSH (1 << 3) /* wait for 'nowait' tasks */ ++#define AuLock_DIRS (1 << 4) /* target is a pair of dirs */ ++ /* except RENAME_EXCHANGE */ ++#define AuLock_NOPLM (1 << 5) /* return err in plm mode */ ++#define AuLock_NOPLMW (1 << 6) /* wait for plm mode ends */ ++#define AuLock_GEN (1 << 7) /* test digen/iigen */ ++#define au_ftest_lock(flags, name) ((flags) & AuLock_##name) ++#define au_fset_lock(flags, name) \ ++ do { (flags) |= AuLock_##name; } while (0) ++#define au_fclr_lock(flags, name) \ ++ do { (flags) &= ~AuLock_##name; } while (0) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* super.c */ ++struct inode *au_iget_locked(struct super_block *sb, ino_t ino); ++ ++typedef unsigned long long (*au_arraycb_t)(struct super_block *sb, void *array, ++ unsigned long long max, void *arg); ++void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, ++ struct super_block *sb, void *arg); ++struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max); ++void au_iarray_free(struct inode **a, unsigned long long max); ++ ++void au_remount_refresh(struct super_block *sb, unsigned int do_idop); ++extern const struct super_operations aufs_sop; ++int au_alloc_root(struct super_block *sb); ++extern struct file_system_type aufs_fs_type; ++ ++/* sbinfo.c */ ++void au_si_free(struct kobject *kobj); ++struct au_sbinfo *au_si_alloc(struct super_block *sb); ++int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr, int may_shrink); ++ ++unsigned int au_sigen_inc(struct super_block *sb); ++aufs_bindex_t au_new_br_id(struct super_block *sb); ++ ++int si_read_lock(struct super_block *sb, int flags); ++int si_write_lock(struct super_block *sb, int flags); ++int aufs_read_lock(struct dentry *dentry, int flags); ++void aufs_read_unlock(struct dentry *dentry, int flags); ++void aufs_write_lock(struct dentry *dentry); ++void aufs_write_unlock(struct dentry *dentry); ++int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags); ++void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2); ++ ++/* wbr_policy.c */ ++extern struct au_wbr_copyup_operations au_wbr_copyup_ops[]; ++extern struct au_wbr_create_operations au_wbr_create_ops[]; ++int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst); ++int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex); ++int au_wbr_do_copyup_bu(struct dentry *dentry, aufs_bindex_t btop); ++ ++/* mvdown.c */ ++int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *arg); ++ ++#ifdef CONFIG_AUFS_FHSM ++/* fhsm.c */ ++ ++static inline pid_t au_fhsm_pid(struct au_fhsm *fhsm) ++{ ++ pid_t pid; ++ ++ spin_lock(&fhsm->fhsm_spin); ++ pid = fhsm->fhsm_pid; ++ spin_unlock(&fhsm->fhsm_spin); ++ ++ return pid; ++} ++ ++void au_fhsm_wrote(struct super_block *sb, aufs_bindex_t bindex, int force); ++void au_fhsm_wrote_all(struct super_block *sb, int force); ++int au_fhsm_fd(struct super_block *sb, int oflags); ++int au_fhsm_br_alloc(struct au_branch *br); ++void au_fhsm_set_bottom(struct super_block *sb, aufs_bindex_t bindex); ++void au_fhsm_fin(struct super_block *sb); ++void au_fhsm_init(struct au_sbinfo *sbinfo); ++void au_fhsm_set(struct au_sbinfo *sbinfo, unsigned int sec); ++void au_fhsm_show(struct seq_file *seq, struct au_sbinfo *sbinfo); ++#else ++AuStubVoid(au_fhsm_wrote, struct super_block *sb, aufs_bindex_t bindex, ++ int force) ++AuStubVoid(au_fhsm_wrote_all, struct super_block *sb, int force) ++AuStub(int, au_fhsm_fd, return -EOPNOTSUPP, struct super_block *sb, int oflags) ++AuStub(pid_t, au_fhsm_pid, return 0, struct au_fhsm *fhsm) ++AuStubInt0(au_fhsm_br_alloc, struct au_branch *br) ++AuStubVoid(au_fhsm_set_bottom, struct super_block *sb, aufs_bindex_t bindex) ++AuStubVoid(au_fhsm_fin, struct super_block *sb) ++AuStubVoid(au_fhsm_init, struct au_sbinfo *sbinfo) ++AuStubVoid(au_fhsm_set, struct au_sbinfo *sbinfo, unsigned int sec) ++AuStubVoid(au_fhsm_show, struct seq_file *seq, struct au_sbinfo *sbinfo) ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_sbinfo *au_sbi(struct super_block *sb) ++{ ++ return sb->s_fs_info; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_EXPORT ++int au_test_nfsd(void); ++void au_export_init(struct super_block *sb); ++void au_xigen_inc(struct inode *inode); ++int au_xigen_new(struct inode *inode); ++int au_xigen_set(struct super_block *sb, struct path *path); ++void au_xigen_clr(struct super_block *sb); ++ ++static inline int au_busy_or_stale(void) ++{ ++ if (!au_test_nfsd()) ++ return -EBUSY; ++ return -ESTALE; ++} ++#else ++AuStubInt0(au_test_nfsd, void) ++AuStubVoid(au_export_init, struct super_block *sb) ++AuStubVoid(au_xigen_inc, struct inode *inode) ++AuStubInt0(au_xigen_new, struct inode *inode) ++AuStubInt0(au_xigen_set, struct super_block *sb, struct path *path) ++AuStubVoid(au_xigen_clr, struct super_block *sb) ++AuStub(int, au_busy_or_stale, return -EBUSY, void) ++#endif /* CONFIG_AUFS_EXPORT */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_SBILIST ++/* module.c */ ++extern struct hlist_bl_head au_sbilist; ++ ++static inline void au_sbilist_init(void) ++{ ++ INIT_HLIST_BL_HEAD(&au_sbilist); ++} ++ ++static inline void au_sbilist_add(struct super_block *sb) ++{ ++ au_hbl_add(&au_sbi(sb)->si_list, &au_sbilist); ++} ++ ++static inline void au_sbilist_del(struct super_block *sb) ++{ ++ au_hbl_del(&au_sbi(sb)->si_list, &au_sbilist); ++} ++ ++#ifdef CONFIG_AUFS_MAGIC_SYSRQ ++static inline void au_sbilist_lock(void) ++{ ++ hlist_bl_lock(&au_sbilist); ++} ++ ++static inline void au_sbilist_unlock(void) ++{ ++ hlist_bl_unlock(&au_sbilist); ++} ++#define AuGFP_SBILIST GFP_ATOMIC ++#else ++AuStubVoid(au_sbilist_lock, void) ++AuStubVoid(au_sbilist_unlock, void) ++#define AuGFP_SBILIST GFP_NOFS ++#endif /* CONFIG_AUFS_MAGIC_SYSRQ */ ++#else ++AuStubVoid(au_sbilist_init, void) ++AuStubVoid(au_sbilist_add, struct super_block *sb) ++AuStubVoid(au_sbilist_del, struct super_block *sb) ++AuStubVoid(au_sbilist_lock, void) ++AuStubVoid(au_sbilist_unlock, void) ++#define AuGFP_SBILIST GFP_NOFS ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline void dbgaufs_si_null(struct au_sbinfo *sbinfo) ++{ ++ /* ++ * This function is a dynamic '__init' function actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++#ifdef CONFIG_DEBUG_FS ++ sbinfo->si_dbgaufs = NULL; ++ sbinfo->si_dbgaufs_plink = NULL; ++ sbinfo->si_dbgaufs_xib = NULL; ++#ifdef CONFIG_AUFS_EXPORT ++ sbinfo->si_dbgaufs_xigen = NULL; ++#endif ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* current->atomic_flags */ ++/* this value should never corrupt the ones defined in linux/sched.h */ ++#define PFA_AUFS 0x10 ++ ++TASK_PFA_TEST(AUFS, test_aufs) /* task_test_aufs */ ++TASK_PFA_SET(AUFS, aufs) /* task_set_aufs */ ++TASK_PFA_CLEAR(AUFS, aufs) /* task_clear_aufs */ ++ ++static inline int si_pid_test(struct super_block *sb) ++{ ++ return !!task_test_aufs(current); ++} ++ ++static inline void si_pid_clr(struct super_block *sb) ++{ ++ AuDebugOn(!task_test_aufs(current)); ++ task_clear_aufs(current); ++} ++ ++static inline void si_pid_set(struct super_block *sb) ++{ ++ AuDebugOn(task_test_aufs(current)); ++ task_set_aufs(current); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock superblock. mainly for entry point functions */ ++#define __si_read_lock(sb) au_rw_read_lock(&au_sbi(sb)->si_rwsem) ++#define __si_write_lock(sb) au_rw_write_lock(&au_sbi(sb)->si_rwsem) ++#define __si_read_trylock(sb) au_rw_read_trylock(&au_sbi(sb)->si_rwsem) ++#define __si_write_trylock(sb) au_rw_write_trylock(&au_sbi(sb)->si_rwsem) ++/* ++#define __si_read_trylock_nested(sb) \ ++ au_rw_read_trylock_nested(&au_sbi(sb)->si_rwsem) ++#define __si_write_trylock_nested(sb) \ ++ au_rw_write_trylock_nested(&au_sbi(sb)->si_rwsem) ++*/ ++ ++#define __si_read_unlock(sb) au_rw_read_unlock(&au_sbi(sb)->si_rwsem) ++#define __si_write_unlock(sb) au_rw_write_unlock(&au_sbi(sb)->si_rwsem) ++#define __si_downgrade_lock(sb) au_rw_dgrade_lock(&au_sbi(sb)->si_rwsem) ++ ++#define SiMustNoWaiters(sb) AuRwMustNoWaiters(&au_sbi(sb)->si_rwsem) ++#define SiMustAnyLock(sb) AuRwMustAnyLock(&au_sbi(sb)->si_rwsem) ++#define SiMustWriteLock(sb) AuRwMustWriteLock(&au_sbi(sb)->si_rwsem) ++ ++static inline void si_noflush_read_lock(struct super_block *sb) ++{ ++ __si_read_lock(sb); ++ si_pid_set(sb); ++} ++ ++static inline int si_noflush_read_trylock(struct super_block *sb) ++{ ++ int locked; ++ ++ locked = __si_read_trylock(sb); ++ if (locked) ++ si_pid_set(sb); ++ return locked; ++} ++ ++static inline void si_noflush_write_lock(struct super_block *sb) ++{ ++ __si_write_lock(sb); ++ si_pid_set(sb); ++} ++ ++static inline int si_noflush_write_trylock(struct super_block *sb) ++{ ++ int locked; ++ ++ locked = __si_write_trylock(sb); ++ if (locked) ++ si_pid_set(sb); ++ return locked; ++} ++ ++#if 0 /* reserved */ ++static inline int si_read_trylock(struct super_block *sb, int flags) ++{ ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ return si_noflush_read_trylock(sb); ++} ++#endif ++ ++static inline void si_read_unlock(struct super_block *sb) ++{ ++ si_pid_clr(sb); ++ __si_read_unlock(sb); ++} ++ ++#if 0 /* reserved */ ++static inline int si_write_trylock(struct super_block *sb, int flags) ++{ ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ return si_noflush_write_trylock(sb); ++} ++#endif ++ ++static inline void si_write_unlock(struct super_block *sb) ++{ ++ si_pid_clr(sb); ++ __si_write_unlock(sb); ++} ++ ++#if 0 /* reserved */ ++static inline void si_downgrade_lock(struct super_block *sb) ++{ ++ __si_downgrade_lock(sb); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline aufs_bindex_t au_sbbot(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_bbot; ++} ++ ++static inline unsigned int au_mntflags(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_mntflags; ++} ++ ++static inline unsigned int au_sigen(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_generation; ++} ++ ++static inline struct au_branch *au_sbr(struct super_block *sb, ++ aufs_bindex_t bindex) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_branch[0 + bindex]; ++} ++ ++static inline loff_t au_xi_maxent(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_ximaxent; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_SUPER_H__ */ +diff -Nurp linux-5.15.37/fs/aufs/sysaufs.c linux-5.15.37-aufs/fs/aufs/sysaufs.c +--- linux-5.15.37/fs/aufs/sysaufs.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/sysaufs.c 2022-04-08 20:22:30.615616621 +0300 +@@ -0,0 +1,80 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * sysfs interface and lifetime management ++ * they are necessary regardless sysfs is disabled. ++ */ ++ ++#include ++#include "aufs.h" ++ ++unsigned long sysaufs_si_mask; ++struct kset *sysaufs_kset; ++ ++#define AuSiAttr(_name) { \ ++ .attr = { .name = __stringify(_name), .mode = 0444 }, \ ++ .show = sysaufs_si_##_name, \ ++} ++ ++static struct sysaufs_si_attr sysaufs_si_attr_xi_path = AuSiAttr(xi_path); ++struct attribute *sysaufs_si_attrs[] = { ++ &sysaufs_si_attr_xi_path.attr, ++ NULL, ++}; ++ ++static const struct sysfs_ops au_sbi_ops = { ++ .show = sysaufs_si_show ++}; ++ ++static struct kobj_type au_sbi_ktype = { ++ .release = au_si_free, ++ .sysfs_ops = &au_sbi_ops, ++ .default_attrs = sysaufs_si_attrs ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int sysaufs_si_init(struct au_sbinfo *sbinfo) ++{ ++ int err; ++ ++ sbinfo->si_kobj.kset = sysaufs_kset; ++ /* cf. sysaufs_name() */ ++ err = kobject_init_and_add ++ (&sbinfo->si_kobj, &au_sbi_ktype, /*&sysaufs_kset->kobj*/NULL, ++ SysaufsSiNamePrefix "%lx", sysaufs_si_id(sbinfo)); ++ ++ return err; ++} ++ ++void sysaufs_fin(void) ++{ ++ sysfs_remove_group(&sysaufs_kset->kobj, sysaufs_attr_group); ++ kset_unregister(sysaufs_kset); ++} ++ ++int __init sysaufs_init(void) ++{ ++ int err; ++ ++ do { ++ get_random_bytes(&sysaufs_si_mask, sizeof(sysaufs_si_mask)); ++ } while (!sysaufs_si_mask); ++ ++ err = -EINVAL; ++ sysaufs_kset = kset_create_and_add(AUFS_NAME, NULL, fs_kobj); ++ if (unlikely(!sysaufs_kset)) ++ goto out; ++ err = PTR_ERR(sysaufs_kset); ++ if (IS_ERR(sysaufs_kset)) ++ goto out; ++ err = sysfs_create_group(&sysaufs_kset->kobj, sysaufs_attr_group); ++ if (unlikely(err)) ++ kset_unregister(sysaufs_kset); ++ ++out: ++ return err; ++} +diff -Nurp linux-5.15.37/fs/aufs/sysaufs.h linux-5.15.37-aufs/fs/aufs/sysaufs.h +--- linux-5.15.37/fs/aufs/sysaufs.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/sysaufs.h 2022-04-08 20:22:30.615616621 +0300 +@@ -0,0 +1,89 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * sysfs interface and mount lifetime management ++ */ ++ ++#ifndef __SYSAUFS_H__ ++#define __SYSAUFS_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "module.h" ++ ++struct super_block; ++struct au_sbinfo; ++ ++struct sysaufs_si_attr { ++ struct attribute attr; ++ int (*show)(struct seq_file *seq, struct super_block *sb); ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* sysaufs.c */ ++extern unsigned long sysaufs_si_mask; ++extern struct kset *sysaufs_kset; ++extern struct attribute *sysaufs_si_attrs[]; ++int sysaufs_si_init(struct au_sbinfo *sbinfo); ++int __init sysaufs_init(void); ++void sysaufs_fin(void); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* some people doesn't like to show a pointer in kernel */ ++static inline unsigned long sysaufs_si_id(struct au_sbinfo *sbinfo) ++{ ++ return sysaufs_si_mask ^ (unsigned long)sbinfo; ++} ++ ++#define SysaufsSiNamePrefix "si_" ++#define SysaufsSiNameLen (sizeof(SysaufsSiNamePrefix) + 16) ++static inline void sysaufs_name(struct au_sbinfo *sbinfo, char *name) ++{ ++ snprintf(name, SysaufsSiNameLen, SysaufsSiNamePrefix "%lx", ++ sysaufs_si_id(sbinfo)); ++} ++ ++struct au_branch; ++#ifdef CONFIG_SYSFS ++/* sysfs.c */ ++extern struct attribute_group *sysaufs_attr_group; ++ ++int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb); ++ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, ++ char *buf); ++long au_brinfo_ioctl(struct file *file, unsigned long arg); ++#ifdef CONFIG_COMPAT ++long au_brinfo_compat_ioctl(struct file *file, unsigned long arg); ++#endif ++ ++void sysaufs_br_init(struct au_branch *br); ++void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex); ++void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex); ++ ++#define sysaufs_brs_init() do {} while (0) ++ ++#else ++#define sysaufs_attr_group NULL ++ ++AuStubInt0(sysaufs_si_xi_path, struct seq_file *seq, struct super_block *sb) ++AuStub(ssize_t, sysaufs_si_show, return 0, struct kobject *kobj, ++ struct attribute *attr, char *buf) ++AuStubVoid(sysaufs_br_init, struct au_branch *br) ++AuStubVoid(sysaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex) ++AuStubVoid(sysaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex) ++ ++static inline void sysaufs_brs_init(void) ++{ ++ sysaufs_brs = 0; ++} ++ ++#endif /* CONFIG_SYSFS */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __SYSAUFS_H__ */ +diff -Nurp linux-5.15.37/fs/aufs/sysfs.c linux-5.15.37-aufs/fs/aufs/sysfs.c +--- linux-5.15.37/fs/aufs/sysfs.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/sysfs.c 2022-04-08 20:22:30.615616621 +0300 +@@ -0,0 +1,338 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * sysfs interface ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++static struct attribute *au_attr[] = { ++ NULL, /* need to NULL terminate the list of attributes */ ++}; ++ ++static struct attribute_group sysaufs_attr_group_body = { ++ .attrs = au_attr ++}; ++ ++struct attribute_group *sysaufs_attr_group = &sysaufs_attr_group_body; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb) ++{ ++ int err; ++ ++ SiMustAnyLock(sb); ++ ++ err = 0; ++ if (au_opt_test(au_mntflags(sb), XINO)) { ++ err = au_xino_path(seq, au_sbi(sb)->si_xib); ++ seq_putc(seq, '\n'); ++ } ++ return err; ++} ++ ++/* ++ * the lifetime of branch is independent from the entry under sysfs. ++ * sysfs handles the lifetime of the entry, and never call ->show() after it is ++ * unlinked. ++ */ ++static int sysaufs_si_br(struct seq_file *seq, struct super_block *sb, ++ aufs_bindex_t bindex, int idx) ++{ ++ int err; ++ struct path path; ++ struct dentry *root; ++ struct au_branch *br; ++ au_br_perm_str_t perm; ++ ++ AuDbg("b%d\n", bindex); ++ ++ err = 0; ++ root = sb->s_root; ++ di_read_lock_parent(root, !AuLock_IR); ++ br = au_sbr(sb, bindex); ++ ++ switch (idx) { ++ case AuBrSysfs_BR: ++ path.mnt = au_br_mnt(br); ++ path.dentry = au_h_dptr(root, bindex); ++ err = au_seq_path(seq, &path); ++ if (!err) { ++ au_optstr_br_perm(&perm, br->br_perm); ++ seq_printf(seq, "=%s\n", perm.a); ++ } ++ break; ++ case AuBrSysfs_BRID: ++ seq_printf(seq, "%d\n", br->br_id); ++ break; ++ } ++ di_read_unlock(root, !AuLock_IR); ++ if (unlikely(err || seq_has_overflowed(seq))) ++ err = -E2BIG; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct seq_file *au_seq(char *p, ssize_t len) ++{ ++ struct seq_file *seq; ++ ++ seq = kzalloc(sizeof(*seq), GFP_NOFS); ++ if (seq) { ++ /* mutex_init(&seq.lock); */ ++ seq->buf = p; ++ seq->size = len; ++ return seq; /* success */ ++ } ++ ++ seq = ERR_PTR(-ENOMEM); ++ return seq; ++} ++ ++#define SysaufsBr_PREFIX "br" ++#define SysaufsBrid_PREFIX "brid" ++ ++/* todo: file size may exceed PAGE_SIZE */ ++ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, ++ char *buf) ++{ ++ ssize_t err; ++ int idx; ++ long l; ++ aufs_bindex_t bbot; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ struct seq_file *seq; ++ char *name; ++ struct attribute **cattr; ++ ++ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); ++ sb = sbinfo->si_sb; ++ ++ /* ++ * prevent a race condition between sysfs and aufs. ++ * for instance, sysfs_file_read() calls sysfs_get_active_two() which ++ * prohibits maintaining the sysfs entries. ++ * hew we acquire read lock after sysfs_get_active_two(). ++ * on the other hand, the remount process may maintain the sysfs/aufs ++ * entries after acquiring write lock. ++ * it can cause a deadlock. ++ * simply we gave up processing read here. ++ */ ++ err = -EBUSY; ++ if (unlikely(!si_noflush_read_trylock(sb))) ++ goto out; ++ ++ seq = au_seq(buf, PAGE_SIZE); ++ err = PTR_ERR(seq); ++ if (IS_ERR(seq)) ++ goto out_unlock; ++ ++ name = (void *)attr->name; ++ cattr = sysaufs_si_attrs; ++ while (*cattr) { ++ if (!strcmp(name, (*cattr)->name)) { ++ err = container_of(*cattr, struct sysaufs_si_attr, attr) ++ ->show(seq, sb); ++ goto out_seq; ++ } ++ cattr++; ++ } ++ ++ if (!strncmp(name, SysaufsBrid_PREFIX, ++ sizeof(SysaufsBrid_PREFIX) - 1)) { ++ idx = AuBrSysfs_BRID; ++ name += sizeof(SysaufsBrid_PREFIX) - 1; ++ } else if (!strncmp(name, SysaufsBr_PREFIX, ++ sizeof(SysaufsBr_PREFIX) - 1)) { ++ idx = AuBrSysfs_BR; ++ name += sizeof(SysaufsBr_PREFIX) - 1; ++ } else ++ BUG(); ++ ++ err = kstrtol(name, 10, &l); ++ if (!err) { ++ bbot = au_sbbot(sb); ++ if (l <= bbot) ++ err = sysaufs_si_br(seq, sb, (aufs_bindex_t)l, idx); ++ else ++ err = -ENOENT; ++ } ++ ++out_seq: ++ if (!err) { ++ err = seq->count; ++ /* sysfs limit */ ++ if (unlikely(err == PAGE_SIZE)) ++ err = -EFBIG; ++ } ++ au_kfree_rcu(seq); ++out_unlock: ++ si_read_unlock(sb); ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_brinfo(struct super_block *sb, union aufs_brinfo __user *arg) ++{ ++ int err; ++ int16_t brid; ++ aufs_bindex_t bindex, bbot; ++ size_t sz; ++ char *buf; ++ struct seq_file *seq; ++ struct au_branch *br; ++ ++ si_read_lock(sb, AuLock_FLUSH); ++ bbot = au_sbbot(sb); ++ err = bbot + 1; ++ if (!arg) ++ goto out; ++ ++ err = -ENOMEM; ++ buf = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!buf)) ++ goto out; ++ ++ seq = au_seq(buf, PAGE_SIZE); ++ err = PTR_ERR(seq); ++ if (IS_ERR(seq)) ++ goto out_buf; ++ ++ sz = sizeof(*arg) - offsetof(union aufs_brinfo, path); ++ for (bindex = 0; bindex <= bbot; bindex++, arg++) { ++ /* VERIFY_WRITE */ ++ err = !access_ok(arg, sizeof(*arg)); ++ if (unlikely(err)) ++ break; ++ ++ br = au_sbr(sb, bindex); ++ brid = br->br_id; ++ BUILD_BUG_ON(sizeof(brid) != sizeof(arg->id)); ++ err = __put_user(brid, &arg->id); ++ if (unlikely(err)) ++ break; ++ ++ BUILD_BUG_ON(sizeof(br->br_perm) != sizeof(arg->perm)); ++ err = __put_user(br->br_perm, &arg->perm); ++ if (unlikely(err)) ++ break; ++ ++ err = au_seq_path(seq, &br->br_path); ++ if (unlikely(err)) ++ break; ++ seq_putc(seq, '\0'); ++ if (!seq_has_overflowed(seq)) { ++ err = copy_to_user(arg->path, seq->buf, seq->count); ++ seq->count = 0; ++ if (unlikely(err)) ++ break; ++ } else { ++ err = -E2BIG; ++ goto out_seq; ++ } ++ } ++ if (unlikely(err)) ++ err = -EFAULT; ++ ++out_seq: ++ au_kfree_rcu(seq); ++out_buf: ++ free_page((unsigned long)buf); ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++long au_brinfo_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_brinfo(file->f_path.dentry->d_sb, (void __user *)arg); ++} ++ ++#ifdef CONFIG_COMPAT ++long au_brinfo_compat_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_brinfo(file->f_path.dentry->d_sb, compat_ptr(arg)); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++void sysaufs_br_init(struct au_branch *br) ++{ ++ int i; ++ struct au_brsysfs *br_sysfs; ++ struct attribute *attr; ++ ++ br_sysfs = br->br_sysfs; ++ for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) { ++ attr = &br_sysfs->attr; ++ sysfs_attr_init(attr); ++ attr->name = br_sysfs->name; ++ attr->mode = 0444; ++ br_sysfs++; ++ } ++} ++ ++void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ struct au_branch *br; ++ struct kobject *kobj; ++ struct au_brsysfs *br_sysfs; ++ int i; ++ aufs_bindex_t bbot; ++ ++ if (!sysaufs_brs) ++ return; ++ ++ kobj = &au_sbi(sb)->si_kobj; ++ bbot = au_sbbot(sb); ++ for (; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ br_sysfs = br->br_sysfs; ++ for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) { ++ sysfs_remove_file(kobj, &br_sysfs->attr); ++ br_sysfs++; ++ } ++ } ++} ++ ++void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ int err, i; ++ aufs_bindex_t bbot; ++ struct kobject *kobj; ++ struct au_branch *br; ++ struct au_brsysfs *br_sysfs; ++ ++ if (!sysaufs_brs) ++ return; ++ ++ kobj = &au_sbi(sb)->si_kobj; ++ bbot = au_sbbot(sb); ++ for (; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ br_sysfs = br->br_sysfs; ++ snprintf(br_sysfs[AuBrSysfs_BR].name, sizeof(br_sysfs->name), ++ SysaufsBr_PREFIX "%d", bindex); ++ snprintf(br_sysfs[AuBrSysfs_BRID].name, sizeof(br_sysfs->name), ++ SysaufsBrid_PREFIX "%d", bindex); ++ for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) { ++ err = sysfs_create_file(kobj, &br_sysfs->attr); ++ if (unlikely(err)) ++ pr_warn("failed %s under sysfs(%d)\n", ++ br_sysfs->name, err); ++ br_sysfs++; ++ } ++ } ++} +diff -Nurp linux-5.15.37/fs/aufs/sysrq.c linux-5.15.37-aufs/fs/aufs/sysrq.c +--- linux-5.15.37/fs/aufs/sysrq.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/sysrq.c 2022-04-08 20:22:30.615616621 +0300 +@@ -0,0 +1,136 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * magic sysrq handler ++ */ ++ ++/* #include */ ++#include ++#include "aufs.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void sysrq_sb(struct super_block *sb) ++{ ++ char *plevel; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ struct hlist_bl_head *files; ++ struct hlist_bl_node *pos; ++ struct au_finfo *finfo; ++ struct inode *i; ++ ++ plevel = au_plevel; ++ au_plevel = KERN_WARNING; ++ ++ /* since we define pr_fmt, call printk directly */ ++#define pr(str) printk(KERN_WARNING AUFS_NAME ": " str) ++ ++ sbinfo = au_sbi(sb); ++ printk(KERN_WARNING "si=%lx\n", sysaufs_si_id(sbinfo)); ++ pr("superblock\n"); ++ au_dpri_sb(sb); ++ ++#if 0 /* reserved */ ++ do { ++ int err, i, j, ndentry; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ ++ err = au_dpages_init(&dpages, GFP_ATOMIC); ++ if (unlikely(err)) ++ break; ++ err = au_dcsub_pages(&dpages, sb->s_root, NULL, NULL); ++ if (!err) ++ for (i = 0; i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ ndentry = dpage->ndentry; ++ for (j = 0; j < ndentry; j++) ++ au_dpri_dentry(dpage->dentries[j]); ++ } ++ au_dpages_free(&dpages); ++ } while (0); ++#endif ++ ++ pr("isolated inode\n"); ++ spin_lock(&sb->s_inode_list_lock); ++ list_for_each_entry(i, &sb->s_inodes, i_sb_list) { ++ spin_lock(&i->i_lock); ++ if (hlist_empty(&i->i_dentry)) ++ au_dpri_inode(i); ++ spin_unlock(&i->i_lock); ++ } ++ spin_unlock(&sb->s_inode_list_lock); ++ ++ pr("files\n"); ++ files = &au_sbi(sb)->si_files; ++ hlist_bl_lock(files); ++ hlist_bl_for_each_entry(finfo, pos, files, fi_hlist) { ++ umode_t mode; ++ ++ file = finfo->fi_file; ++ mode = file_inode(file)->i_mode; ++ if (!special_file(mode)) ++ au_dpri_file(file); ++ } ++ hlist_bl_unlock(files); ++ pr("done\n"); ++ ++#undef pr ++ au_plevel = plevel; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* module parameter */ ++static char *aufs_sysrq_key = "a"; ++module_param_named(sysrq, aufs_sysrq_key, charp, 0444); ++MODULE_PARM_DESC(sysrq, "MagicSysRq key for " AUFS_NAME); ++ ++static void au_sysrq(int key __maybe_unused) ++{ ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_node *pos; ++ ++ lockdep_off(); ++ au_sbilist_lock(); ++ hlist_bl_for_each_entry(sbinfo, pos, &au_sbilist, si_list) ++ sysrq_sb(sbinfo->si_sb); ++ au_sbilist_unlock(); ++ lockdep_on(); ++} ++ ++static struct sysrq_key_op au_sysrq_op = { ++ .handler = au_sysrq, ++ .help_msg = "Aufs", ++ .action_msg = "Aufs", ++ .enable_mask = SYSRQ_ENABLE_DUMP ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int __init au_sysrq_init(void) ++{ ++ int err; ++ char key; ++ ++ err = -1; ++ key = *aufs_sysrq_key; ++ if ('a' <= key && key <= 'z') ++ err = register_sysrq_key(key, &au_sysrq_op); ++ if (unlikely(err)) ++ pr_err("err %d, sysrq=%c\n", err, key); ++ return err; ++} ++ ++void au_sysrq_fin(void) ++{ ++ int err; ++ ++ err = unregister_sysrq_key(*aufs_sysrq_key, &au_sysrq_op); ++ if (unlikely(err)) ++ pr_err("err %d (ignored)\n", err); ++} +diff -Nurp linux-5.15.37/fs/aufs/vdir.c linux-5.15.37-aufs/fs/aufs/vdir.c +--- linux-5.15.37/fs/aufs/vdir.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/vdir.c 2022-04-08 20:22:30.615616621 +0300 +@@ -0,0 +1,883 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * virtual or vertical directory ++ */ ++ ++#include ++#include "aufs.h" ++ ++static unsigned int calc_size(int nlen) ++{ ++ return ALIGN(sizeof(struct au_vdir_de) + nlen, sizeof(ino_t)); ++} ++ ++static int set_deblk_end(union au_vdir_deblk_p *p, ++ union au_vdir_deblk_p *deblk_end) ++{ ++ if (calc_size(0) <= deblk_end->deblk - p->deblk) { ++ p->de->de_str.len = 0; ++ /* smp_mb(); */ ++ return 0; ++ } ++ return -1; /* error */ ++} ++ ++/* returns true or false */ ++static int is_deblk_end(union au_vdir_deblk_p *p, ++ union au_vdir_deblk_p *deblk_end) ++{ ++ if (calc_size(0) <= deblk_end->deblk - p->deblk) ++ return !p->de->de_str.len; ++ return 1; ++} ++ ++static unsigned char *last_deblk(struct au_vdir *vdir) ++{ ++ return vdir->vd_deblk[vdir->vd_nblk - 1]; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* estimate the appropriate size for name hash table */ ++unsigned int au_rdhash_est(loff_t sz) ++{ ++ unsigned int n; ++ ++ n = UINT_MAX; ++ sz >>= 10; ++ if (sz < n) ++ n = sz; ++ if (sz < AUFS_RDHASH_DEF) ++ n = AUFS_RDHASH_DEF; ++ /* pr_info("n %u\n", n); */ ++ return n; ++} ++ ++/* ++ * the allocated memory has to be freed by ++ * au_nhash_wh_free() or au_nhash_de_free(). ++ */ ++int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp) ++{ ++ struct hlist_head *head; ++ unsigned int u; ++ size_t sz; ++ ++ sz = sizeof(*nhash->nh_head) * num_hash; ++ head = kmalloc(sz, gfp); ++ if (head) { ++ nhash->nh_num = num_hash; ++ nhash->nh_head = head; ++ for (u = 0; u < num_hash; u++) ++ INIT_HLIST_HEAD(head++); ++ return 0; /* success */ ++ } ++ ++ return -ENOMEM; ++} ++ ++static void nhash_count(struct hlist_head *head) ++{ ++#if 0 /* debugging */ ++ unsigned long n; ++ struct hlist_node *pos; ++ ++ n = 0; ++ hlist_for_each(pos, head) ++ n++; ++ pr_info("%lu\n", n); ++#endif ++} ++ ++static void au_nhash_wh_do_free(struct hlist_head *head) ++{ ++ struct au_vdir_wh *pos; ++ struct hlist_node *node; ++ ++ hlist_for_each_entry_safe(pos, node, head, wh_hash) ++ au_kfree_rcu(pos); ++} ++ ++static void au_nhash_de_do_free(struct hlist_head *head) ++{ ++ struct au_vdir_dehstr *pos; ++ struct hlist_node *node; ++ ++ hlist_for_each_entry_safe(pos, node, head, hash) ++ au_cache_free_vdir_dehstr(pos); ++} ++ ++static void au_nhash_do_free(struct au_nhash *nhash, ++ void (*free)(struct hlist_head *head)) ++{ ++ unsigned int n; ++ struct hlist_head *head; ++ ++ n = nhash->nh_num; ++ if (!n) ++ return; ++ ++ head = nhash->nh_head; ++ while (n-- > 0) { ++ nhash_count(head); ++ free(head++); ++ } ++ au_kfree_try_rcu(nhash->nh_head); ++} ++ ++void au_nhash_wh_free(struct au_nhash *whlist) ++{ ++ au_nhash_do_free(whlist, au_nhash_wh_do_free); ++} ++ ++static void au_nhash_de_free(struct au_nhash *delist) ++{ ++ au_nhash_do_free(delist, au_nhash_de_do_free); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt, ++ int limit) ++{ ++ int num; ++ unsigned int u, n; ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ ++ num = 0; ++ n = whlist->nh_num; ++ head = whlist->nh_head; ++ for (u = 0; u < n; u++, head++) ++ hlist_for_each_entry(pos, head, wh_hash) ++ if (pos->wh_bindex == btgt && ++num > limit) ++ return 1; ++ return 0; ++} ++ ++static struct hlist_head *au_name_hash(struct au_nhash *nhash, ++ unsigned char *name, ++ unsigned int len) ++{ ++ unsigned int v; ++ /* const unsigned int magic_bit = 12; */ ++ ++ AuDebugOn(!nhash->nh_num || !nhash->nh_head); ++ ++ v = 0; ++ if (len > 8) ++ len = 8; ++ while (len--) ++ v += *name++; ++ /* v = hash_long(v, magic_bit); */ ++ v %= nhash->nh_num; ++ return nhash->nh_head + v; ++} ++ ++static int au_nhash_test_name(struct au_vdir_destr *str, const char *name, ++ int nlen) ++{ ++ return str->len == nlen && !memcmp(str->name, name, nlen); ++} ++ ++/* returns found or not */ ++int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen) ++{ ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ struct au_vdir_destr *str; ++ ++ head = au_name_hash(whlist, name, nlen); ++ hlist_for_each_entry(pos, head, wh_hash) { ++ str = &pos->wh_str; ++ AuDbg("%.*s\n", str->len, str->name); ++ if (au_nhash_test_name(str, name, nlen)) ++ return 1; ++ } ++ return 0; ++} ++ ++/* returns found(true) or not */ ++static int test_known(struct au_nhash *delist, char *name, int nlen) ++{ ++ struct hlist_head *head; ++ struct au_vdir_dehstr *pos; ++ struct au_vdir_destr *str; ++ ++ head = au_name_hash(delist, name, nlen); ++ hlist_for_each_entry(pos, head, hash) { ++ str = pos->str; ++ AuDbg("%.*s\n", str->len, str->name); ++ if (au_nhash_test_name(str, name, nlen)) ++ return 1; ++ } ++ return 0; ++} ++ ++static void au_shwh_init_wh(struct au_vdir_wh *wh, ino_t ino, ++ unsigned char d_type) ++{ ++#ifdef CONFIG_AUFS_SHWH ++ wh->wh_ino = ino; ++ wh->wh_type = d_type; ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino, ++ unsigned int d_type, aufs_bindex_t bindex, ++ unsigned char shwh) ++{ ++ int err; ++ struct au_vdir_destr *str; ++ struct au_vdir_wh *wh; ++ ++ AuDbg("%.*s\n", nlen, name); ++ AuDebugOn(!whlist->nh_num || !whlist->nh_head); ++ ++ err = -ENOMEM; ++ wh = kmalloc(sizeof(*wh) + nlen, GFP_NOFS); ++ if (unlikely(!wh)) ++ goto out; ++ ++ err = 0; ++ wh->wh_bindex = bindex; ++ if (shwh) ++ au_shwh_init_wh(wh, ino, d_type); ++ str = &wh->wh_str; ++ str->len = nlen; ++ memcpy(str->name, name, nlen); ++ hlist_add_head(&wh->wh_hash, au_name_hash(whlist, name, nlen)); ++ /* smp_mb(); */ ++ ++out: ++ return err; ++} ++ ++static int append_deblk(struct au_vdir *vdir) ++{ ++ int err; ++ unsigned long ul; ++ const unsigned int deblk_sz = vdir->vd_deblk_sz; ++ union au_vdir_deblk_p p, deblk_end; ++ unsigned char **o; ++ ++ err = -ENOMEM; ++ o = au_krealloc(vdir->vd_deblk, sizeof(*o) * (vdir->vd_nblk + 1), ++ GFP_NOFS, /*may_shrink*/0); ++ if (unlikely(!o)) ++ goto out; ++ ++ vdir->vd_deblk = o; ++ p.deblk = kmalloc(deblk_sz, GFP_NOFS); ++ if (p.deblk) { ++ ul = vdir->vd_nblk++; ++ vdir->vd_deblk[ul] = p.deblk; ++ vdir->vd_last.ul = ul; ++ vdir->vd_last.p.deblk = p.deblk; ++ deblk_end.deblk = p.deblk + deblk_sz; ++ err = set_deblk_end(&p, &deblk_end); ++ } ++ ++out: ++ return err; ++} ++ ++static int append_de(struct au_vdir *vdir, char *name, int nlen, ino_t ino, ++ unsigned int d_type, struct au_nhash *delist) ++{ ++ int err; ++ unsigned int sz; ++ const unsigned int deblk_sz = vdir->vd_deblk_sz; ++ union au_vdir_deblk_p p, *room, deblk_end; ++ struct au_vdir_dehstr *dehstr; ++ ++ p.deblk = last_deblk(vdir); ++ deblk_end.deblk = p.deblk + deblk_sz; ++ room = &vdir->vd_last.p; ++ AuDebugOn(room->deblk < p.deblk || deblk_end.deblk <= room->deblk ++ || !is_deblk_end(room, &deblk_end)); ++ ++ sz = calc_size(nlen); ++ if (unlikely(sz > deblk_end.deblk - room->deblk)) { ++ err = append_deblk(vdir); ++ if (unlikely(err)) ++ goto out; ++ ++ p.deblk = last_deblk(vdir); ++ deblk_end.deblk = p.deblk + deblk_sz; ++ /* smp_mb(); */ ++ AuDebugOn(room->deblk != p.deblk); ++ } ++ ++ err = -ENOMEM; ++ dehstr = au_cache_alloc_vdir_dehstr(); ++ if (unlikely(!dehstr)) ++ goto out; ++ ++ dehstr->str = &room->de->de_str; ++ hlist_add_head(&dehstr->hash, au_name_hash(delist, name, nlen)); ++ room->de->de_ino = ino; ++ room->de->de_type = d_type; ++ room->de->de_str.len = nlen; ++ memcpy(room->de->de_str.name, name, nlen); ++ ++ err = 0; ++ room->deblk += sz; ++ if (unlikely(set_deblk_end(room, &deblk_end))) ++ err = append_deblk(vdir); ++ /* smp_mb(); */ ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_vdir_free(struct au_vdir *vdir) ++{ ++ unsigned char **deblk; ++ ++ deblk = vdir->vd_deblk; ++ while (vdir->vd_nblk--) ++ au_kfree_try_rcu(*deblk++); ++ au_kfree_try_rcu(vdir->vd_deblk); ++ au_cache_free_vdir(vdir); ++} ++ ++static struct au_vdir *alloc_vdir(struct file *file) ++{ ++ struct au_vdir *vdir; ++ struct super_block *sb; ++ int err; ++ ++ sb = file->f_path.dentry->d_sb; ++ SiMustAnyLock(sb); ++ ++ err = -ENOMEM; ++ vdir = au_cache_alloc_vdir(); ++ if (unlikely(!vdir)) ++ goto out; ++ ++ vdir->vd_deblk = kzalloc(sizeof(*vdir->vd_deblk), GFP_NOFS); ++ if (unlikely(!vdir->vd_deblk)) ++ goto out_free; ++ ++ vdir->vd_deblk_sz = au_sbi(sb)->si_rdblk; ++ if (!vdir->vd_deblk_sz) { ++ /* estimate the appropriate size for deblk */ ++ vdir->vd_deblk_sz = au_dir_size(file, /*dentry*/NULL); ++ /* pr_info("vd_deblk_sz %u\n", vdir->vd_deblk_sz); */ ++ } ++ vdir->vd_nblk = 0; ++ vdir->vd_version = 0; ++ vdir->vd_jiffy = 0; ++ err = append_deblk(vdir); ++ if (!err) ++ return vdir; /* success */ ++ ++ au_kfree_try_rcu(vdir->vd_deblk); ++ ++out_free: ++ au_cache_free_vdir(vdir); ++out: ++ vdir = ERR_PTR(err); ++ return vdir; ++} ++ ++static int reinit_vdir(struct au_vdir *vdir) ++{ ++ int err; ++ union au_vdir_deblk_p p, deblk_end; ++ ++ while (vdir->vd_nblk > 1) { ++ au_kfree_try_rcu(vdir->vd_deblk[vdir->vd_nblk - 1]); ++ /* vdir->vd_deblk[vdir->vd_nblk - 1] = NULL; */ ++ vdir->vd_nblk--; ++ } ++ p.deblk = vdir->vd_deblk[0]; ++ deblk_end.deblk = p.deblk + vdir->vd_deblk_sz; ++ err = set_deblk_end(&p, &deblk_end); ++ /* keep vd_dblk_sz */ ++ vdir->vd_last.ul = 0; ++ vdir->vd_last.p.deblk = vdir->vd_deblk[0]; ++ vdir->vd_version = 0; ++ vdir->vd_jiffy = 0; ++ /* smp_mb(); */ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define AuFillVdir_CALLED 1 ++#define AuFillVdir_WHABLE (1 << 1) ++#define AuFillVdir_SHWH (1 << 2) ++#define au_ftest_fillvdir(flags, name) ((flags) & AuFillVdir_##name) ++#define au_fset_fillvdir(flags, name) \ ++ do { (flags) |= AuFillVdir_##name; } while (0) ++#define au_fclr_fillvdir(flags, name) \ ++ do { (flags) &= ~AuFillVdir_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_SHWH ++#undef AuFillVdir_SHWH ++#define AuFillVdir_SHWH 0 ++#endif ++ ++struct fillvdir_arg { ++ struct dir_context ctx; ++ struct file *file; ++ struct au_vdir *vdir; ++ struct au_nhash delist; ++ struct au_nhash whlist; ++ aufs_bindex_t bindex; ++ unsigned int flags; ++ int err; ++}; ++ ++static int fillvdir(struct dir_context *ctx, const char *__name, int nlen, ++ loff_t offset __maybe_unused, u64 h_ino, ++ unsigned int d_type) ++{ ++ struct fillvdir_arg *arg = container_of(ctx, struct fillvdir_arg, ctx); ++ char *name = (void *)__name; ++ struct super_block *sb; ++ ino_t ino; ++ const unsigned char shwh = !!au_ftest_fillvdir(arg->flags, SHWH); ++ ++ arg->err = 0; ++ sb = arg->file->f_path.dentry->d_sb; ++ au_fset_fillvdir(arg->flags, CALLED); ++ /* smp_mb(); */ ++ if (nlen <= AUFS_WH_PFX_LEN ++ || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { ++ if (test_known(&arg->delist, name, nlen) ++ || au_nhash_test_known_wh(&arg->whlist, name, nlen)) ++ goto out; /* already exists or whiteouted */ ++ ++ arg->err = au_ino(sb, arg->bindex, h_ino, d_type, &ino); ++ if (!arg->err) { ++ if (unlikely(nlen > AUFS_MAX_NAMELEN)) ++ d_type = DT_UNKNOWN; ++ arg->err = append_de(arg->vdir, name, nlen, ino, ++ d_type, &arg->delist); ++ } ++ } else if (au_ftest_fillvdir(arg->flags, WHABLE)) { ++ name += AUFS_WH_PFX_LEN; ++ nlen -= AUFS_WH_PFX_LEN; ++ if (au_nhash_test_known_wh(&arg->whlist, name, nlen)) ++ goto out; /* already whiteouted */ ++ ++ ino = 0; /* just to suppress a warning */ ++ if (shwh) ++ arg->err = au_wh_ino(sb, arg->bindex, h_ino, d_type, ++ &ino); ++ if (!arg->err) { ++ if (nlen <= AUFS_MAX_NAMELEN + AUFS_WH_PFX_LEN) ++ d_type = DT_UNKNOWN; ++ arg->err = au_nhash_append_wh ++ (&arg->whlist, name, nlen, ino, d_type, ++ arg->bindex, shwh); ++ } ++ } ++ ++out: ++ if (!arg->err) ++ arg->vdir->vd_jiffy = jiffies; ++ /* smp_mb(); */ ++ AuTraceErr(arg->err); ++ return arg->err; ++} ++ ++static int au_handle_shwh(struct super_block *sb, struct au_vdir *vdir, ++ struct au_nhash *whlist, struct au_nhash *delist) ++{ ++#ifdef CONFIG_AUFS_SHWH ++ int err; ++ unsigned int nh, u; ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ struct hlist_node *n; ++ char *p, *o; ++ struct au_vdir_destr *destr; ++ ++ AuDebugOn(!au_opt_test(au_mntflags(sb), SHWH)); ++ ++ err = -ENOMEM; ++ o = p = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!p)) ++ goto out; ++ ++ err = 0; ++ nh = whlist->nh_num; ++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); ++ p += AUFS_WH_PFX_LEN; ++ for (u = 0; u < nh; u++) { ++ head = whlist->nh_head + u; ++ hlist_for_each_entry_safe(pos, n, head, wh_hash) { ++ destr = &pos->wh_str; ++ memcpy(p, destr->name, destr->len); ++ err = append_de(vdir, o, destr->len + AUFS_WH_PFX_LEN, ++ pos->wh_ino, pos->wh_type, delist); ++ if (unlikely(err)) ++ break; ++ } ++ } ++ ++ free_page((unsigned long)o); ++ ++out: ++ AuTraceErr(err); ++ return err; ++#else ++ return 0; ++#endif ++} ++ ++static int au_do_read_vdir(struct fillvdir_arg *arg) ++{ ++ int err; ++ unsigned int rdhash; ++ loff_t offset; ++ aufs_bindex_t bbot, bindex, btop; ++ unsigned char shwh; ++ struct file *hf, *file; ++ struct super_block *sb; ++ ++ file = arg->file; ++ sb = file->f_path.dentry->d_sb; ++ SiMustAnyLock(sb); ++ ++ rdhash = au_sbi(sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(file, /*dentry*/NULL)); ++ err = au_nhash_alloc(&arg->delist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_nhash_alloc(&arg->whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out_delist; ++ ++ err = 0; ++ arg->flags = 0; ++ shwh = 0; ++ if (au_opt_test(au_mntflags(sb), SHWH)) { ++ shwh = 1; ++ au_fset_fillvdir(arg->flags, SHWH); ++ } ++ btop = au_fbtop(file); ++ bbot = au_fbbot_dir(file); ++ for (bindex = btop; !err && bindex <= bbot; bindex++) { ++ hf = au_hf_dir(file, bindex); ++ if (!hf) ++ continue; ++ ++ offset = vfsub_llseek(hf, 0, SEEK_SET); ++ err = offset; ++ if (unlikely(offset)) ++ break; ++ ++ arg->bindex = bindex; ++ au_fclr_fillvdir(arg->flags, WHABLE); ++ if (shwh ++ || (bindex != bbot ++ && au_br_whable(au_sbr_perm(sb, bindex)))) ++ au_fset_fillvdir(arg->flags, WHABLE); ++ do { ++ arg->err = 0; ++ au_fclr_fillvdir(arg->flags, CALLED); ++ /* smp_mb(); */ ++ err = vfsub_iterate_dir(hf, &arg->ctx); ++ if (err >= 0) ++ err = arg->err; ++ } while (!err && au_ftest_fillvdir(arg->flags, CALLED)); ++ ++ /* ++ * dir_relax() may be good for concurrency, but aufs should not ++ * use it since it will cause a lockdep problem. ++ */ ++ } ++ ++ if (!err && shwh) ++ err = au_handle_shwh(sb, arg->vdir, &arg->whlist, &arg->delist); ++ ++ au_nhash_wh_free(&arg->whlist); ++ ++out_delist: ++ au_nhash_de_free(&arg->delist); ++out: ++ return err; ++} ++ ++static int read_vdir(struct file *file, int may_read) ++{ ++ int err; ++ unsigned long expire; ++ unsigned char do_read; ++ struct fillvdir_arg arg = { ++ .ctx = { ++ .actor = fillvdir ++ } ++ }; ++ struct inode *inode; ++ struct au_vdir *vdir, *allocated; ++ ++ err = 0; ++ inode = file_inode(file); ++ IMustLock(inode); ++ IiMustWriteLock(inode); ++ SiMustAnyLock(inode->i_sb); ++ ++ allocated = NULL; ++ do_read = 0; ++ expire = au_sbi(inode->i_sb)->si_rdcache; ++ vdir = au_ivdir(inode); ++ if (!vdir) { ++ do_read = 1; ++ vdir = alloc_vdir(file); ++ err = PTR_ERR(vdir); ++ if (IS_ERR(vdir)) ++ goto out; ++ err = 0; ++ allocated = vdir; ++ } else if (may_read ++ && (!inode_eq_iversion(inode, vdir->vd_version) ++ || time_after(jiffies, vdir->vd_jiffy + expire))) { ++ do_read = 1; ++ err = reinit_vdir(vdir); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ if (!do_read) ++ return 0; /* success */ ++ ++ arg.file = file; ++ arg.vdir = vdir; ++ err = au_do_read_vdir(&arg); ++ if (!err) { ++ /* file->f_pos = 0; */ /* todo: ctx->pos? */ ++ vdir->vd_version = inode_query_iversion(inode); ++ vdir->vd_last.ul = 0; ++ vdir->vd_last.p.deblk = vdir->vd_deblk[0]; ++ if (allocated) ++ au_set_ivdir(inode, allocated); ++ } else if (allocated) ++ au_vdir_free(allocated); ++ ++out: ++ return err; ++} ++ ++static int copy_vdir(struct au_vdir *tgt, struct au_vdir *src) ++{ ++ int err, rerr; ++ unsigned long ul, n; ++ const unsigned int deblk_sz = src->vd_deblk_sz; ++ ++ AuDebugOn(tgt->vd_nblk != 1); ++ ++ err = -ENOMEM; ++ if (tgt->vd_nblk < src->vd_nblk) { ++ unsigned char **p; ++ ++ p = au_krealloc(tgt->vd_deblk, sizeof(*p) * src->vd_nblk, ++ GFP_NOFS, /*may_shrink*/0); ++ if (unlikely(!p)) ++ goto out; ++ tgt->vd_deblk = p; ++ } ++ ++ if (tgt->vd_deblk_sz != deblk_sz) { ++ unsigned char *p; ++ ++ tgt->vd_deblk_sz = deblk_sz; ++ p = au_krealloc(tgt->vd_deblk[0], deblk_sz, GFP_NOFS, ++ /*may_shrink*/1); ++ if (unlikely(!p)) ++ goto out; ++ tgt->vd_deblk[0] = p; ++ } ++ memcpy(tgt->vd_deblk[0], src->vd_deblk[0], deblk_sz); ++ tgt->vd_version = src->vd_version; ++ tgt->vd_jiffy = src->vd_jiffy; ++ ++ n = src->vd_nblk; ++ for (ul = 1; ul < n; ul++) { ++ tgt->vd_deblk[ul] = kmemdup(src->vd_deblk[ul], deblk_sz, ++ GFP_NOFS); ++ if (unlikely(!tgt->vd_deblk[ul])) ++ goto out; ++ tgt->vd_nblk++; ++ } ++ tgt->vd_nblk = n; ++ tgt->vd_last.ul = tgt->vd_last.ul; ++ tgt->vd_last.p.deblk = tgt->vd_deblk[tgt->vd_last.ul]; ++ tgt->vd_last.p.deblk += src->vd_last.p.deblk ++ - src->vd_deblk[src->vd_last.ul]; ++ /* smp_mb(); */ ++ return 0; /* success */ ++ ++out: ++ rerr = reinit_vdir(tgt); ++ BUG_ON(rerr); ++ return err; ++} ++ ++int au_vdir_init(struct file *file) ++{ ++ int err; ++ struct inode *inode; ++ struct au_vdir *vdir_cache, *allocated; ++ ++ /* test file->f_pos here instead of ctx->pos */ ++ err = read_vdir(file, !file->f_pos); ++ if (unlikely(err)) ++ goto out; ++ ++ allocated = NULL; ++ vdir_cache = au_fvdir_cache(file); ++ if (!vdir_cache) { ++ vdir_cache = alloc_vdir(file); ++ err = PTR_ERR(vdir_cache); ++ if (IS_ERR(vdir_cache)) ++ goto out; ++ allocated = vdir_cache; ++ } else if (!file->f_pos && vdir_cache->vd_version != file->f_version) { ++ /* test file->f_pos here instead of ctx->pos */ ++ err = reinit_vdir(vdir_cache); ++ if (unlikely(err)) ++ goto out; ++ } else ++ return 0; /* success */ ++ ++ inode = file_inode(file); ++ err = copy_vdir(vdir_cache, au_ivdir(inode)); ++ if (!err) { ++ file->f_version = inode_query_iversion(inode); ++ if (allocated) ++ au_set_fvdir_cache(file, allocated); ++ } else if (allocated) ++ au_vdir_free(allocated); ++ ++out: ++ return err; ++} ++ ++static loff_t calc_offset(struct au_vdir *vdir) ++{ ++ loff_t offset; ++ union au_vdir_deblk_p p; ++ ++ p.deblk = vdir->vd_deblk[vdir->vd_last.ul]; ++ offset = vdir->vd_last.p.deblk - p.deblk; ++ offset += vdir->vd_deblk_sz * vdir->vd_last.ul; ++ return offset; ++} ++ ++/* returns true or false */ ++static int seek_vdir(struct file *file, struct dir_context *ctx) ++{ ++ int valid; ++ unsigned int deblk_sz; ++ unsigned long ul, n; ++ loff_t offset; ++ union au_vdir_deblk_p p, deblk_end; ++ struct au_vdir *vdir_cache; ++ ++ valid = 1; ++ vdir_cache = au_fvdir_cache(file); ++ offset = calc_offset(vdir_cache); ++ AuDbg("offset %lld\n", offset); ++ if (ctx->pos == offset) ++ goto out; ++ ++ vdir_cache->vd_last.ul = 0; ++ vdir_cache->vd_last.p.deblk = vdir_cache->vd_deblk[0]; ++ if (!ctx->pos) ++ goto out; ++ ++ valid = 0; ++ deblk_sz = vdir_cache->vd_deblk_sz; ++ ul = div64_u64(ctx->pos, deblk_sz); ++ AuDbg("ul %lu\n", ul); ++ if (ul >= vdir_cache->vd_nblk) ++ goto out; ++ ++ n = vdir_cache->vd_nblk; ++ for (; ul < n; ul++) { ++ p.deblk = vdir_cache->vd_deblk[ul]; ++ deblk_end.deblk = p.deblk + deblk_sz; ++ offset = ul; ++ offset *= deblk_sz; ++ while (!is_deblk_end(&p, &deblk_end) && offset < ctx->pos) { ++ unsigned int l; ++ ++ l = calc_size(p.de->de_str.len); ++ offset += l; ++ p.deblk += l; ++ } ++ if (!is_deblk_end(&p, &deblk_end)) { ++ valid = 1; ++ vdir_cache->vd_last.ul = ul; ++ vdir_cache->vd_last.p = p; ++ break; ++ } ++ } ++ ++out: ++ /* smp_mb(); */ ++ if (!valid) ++ AuDbg("valid %d\n", !valid); ++ return valid; ++} ++ ++int au_vdir_fill_de(struct file *file, struct dir_context *ctx) ++{ ++ unsigned int l, deblk_sz; ++ union au_vdir_deblk_p deblk_end; ++ struct au_vdir *vdir_cache; ++ struct au_vdir_de *de; ++ ++ if (!seek_vdir(file, ctx)) ++ return 0; ++ ++ vdir_cache = au_fvdir_cache(file); ++ deblk_sz = vdir_cache->vd_deblk_sz; ++ while (1) { ++ deblk_end.deblk = vdir_cache->vd_deblk[vdir_cache->vd_last.ul]; ++ deblk_end.deblk += deblk_sz; ++ while (!is_deblk_end(&vdir_cache->vd_last.p, &deblk_end)) { ++ de = vdir_cache->vd_last.p.de; ++ AuDbg("%.*s, off%lld, i%lu, dt%d\n", ++ de->de_str.len, de->de_str.name, ctx->pos, ++ (unsigned long)de->de_ino, de->de_type); ++ if (unlikely(!dir_emit(ctx, de->de_str.name, ++ de->de_str.len, de->de_ino, ++ de->de_type))) { ++ /* todo: ignore the error caused by udba? */ ++ /* return err; */ ++ return 0; ++ } ++ ++ l = calc_size(de->de_str.len); ++ vdir_cache->vd_last.p.deblk += l; ++ ctx->pos += l; ++ } ++ if (vdir_cache->vd_last.ul < vdir_cache->vd_nblk - 1) { ++ vdir_cache->vd_last.ul++; ++ vdir_cache->vd_last.p.deblk ++ = vdir_cache->vd_deblk[vdir_cache->vd_last.ul]; ++ ctx->pos = deblk_sz * vdir_cache->vd_last.ul; ++ continue; ++ } ++ break; ++ } ++ ++ /* smp_mb(); */ ++ return 0; ++} +diff -Nurp linux-5.15.37/fs/aufs/vfsub.c linux-5.15.37-aufs/fs/aufs/vfsub.c +--- linux-5.15.37/fs/aufs/vfsub.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/vfsub.c 2022-04-08 20:22:30.616616670 +0300 +@@ -0,0 +1,905 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * sub-routines for VFS ++ */ ++ ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++#ifdef CONFIG_AUFS_BR_FUSE ++int vfsub_test_mntns(struct vfsmount *mnt, struct super_block *h_sb) ++{ ++ if (!au_test_fuse(h_sb) || !au_userns) ++ return 0; ++ ++ return is_current_mnt_ns(mnt) ? 0 : -EACCES; ++} ++#endif ++ ++int vfsub_sync_filesystem(struct super_block *h_sb) ++{ ++ int err; ++ ++ lockdep_off(); ++ down_read(&h_sb->s_umount); ++ err = sync_filesystem(h_sb); ++ up_read(&h_sb->s_umount); ++ lockdep_on(); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int vfsub_update_h_iattr(struct path *h_path, int *did) ++{ ++ int err; ++ struct kstat st; ++ struct super_block *h_sb; ++ ++ /* ++ * Always needs h_path->mnt for LSM or FUSE branch. ++ */ ++ AuDebugOn(!h_path->mnt); ++ ++ /* for remote fs, leave work for its getattr or d_revalidate */ ++ /* for bad i_attr fs, handle them in aufs_getattr() */ ++ /* still some fs may acquire i_mutex. we need to skip them */ ++ err = 0; ++ if (!did) ++ did = &err; ++ h_sb = h_path->dentry->d_sb; ++ *did = (!au_test_fs_remote(h_sb) && au_test_fs_refresh_iattr(h_sb)); ++ if (*did) ++ err = vfsub_getattr(h_path, &st); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct file *vfsub_dentry_open(struct path *path, int flags) ++{ ++ return dentry_open(path, flags /* | __FMODE_NONOTIFY */, ++ current_cred()); ++} ++ ++struct file *vfsub_filp_open(const char *path, int oflags, int mode) ++{ ++ struct file *file; ++ ++ lockdep_off(); ++ file = filp_open(path, ++ oflags /* | __FMODE_NONOTIFY */, ++ mode); ++ lockdep_on(); ++ if (IS_ERR(file)) ++ goto out; ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ ++out: ++ return file; ++} ++ ++/* ++ * Ideally this function should call VFS:do_last() in order to keep all its ++ * checkings. But it is very hard for aufs to regenerate several VFS internal ++ * structure such as nameidata. This is a second (or third) best approach. ++ * cf. linux/fs/namei.c:do_last(), lookup_open() and atomic_open(). ++ */ ++int vfsub_atomic_open(struct inode *dir, struct dentry *dentry, ++ struct vfsub_aopen_args *args) ++{ ++ int err; ++ struct au_branch *br = args->br; ++ struct file *file = args->file; ++ /* copied from linux/fs/namei.c:atomic_open() */ ++ struct dentry *const DENTRY_NOT_SET = (void *)-1UL; ++ ++ IMustLock(dir); ++ AuDebugOn(!dir->i_op->atomic_open); ++ ++ err = au_br_test_oflag(args->open_flag, br); ++ if (unlikely(err)) ++ goto out; ++ ++ au_lcnt_inc(&br->br_nfiles); ++ file->f_path.dentry = DENTRY_NOT_SET; ++ file->f_path.mnt = au_br_mnt(br); ++ AuDbg("%ps\n", dir->i_op->atomic_open); ++ err = dir->i_op->atomic_open(dir, dentry, file, args->open_flag, ++ args->create_mode); ++ if (unlikely(err < 0)) { ++ au_lcnt_dec(&br->br_nfiles); ++ goto out; ++ } ++ ++ /* temporary workaround for nfsv4 branch */ ++ if (au_test_nfs(dir->i_sb)) ++ nfs_mark_for_revalidate(dir); ++ ++ if (file->f_mode & FMODE_CREATED) ++ fsnotify_create(dir, dentry); ++ if (!(file->f_mode & FMODE_OPENED)) { ++ au_lcnt_dec(&br->br_nfiles); ++ goto out; ++ } ++ ++ /* todo: call VFS:may_open() here */ ++ /* todo: ima_file_check() too? */ ++ if (!err && (args->open_flag & __FMODE_EXEC)) ++ err = deny_write_access(file); ++ if (!err) ++ fsnotify_open(file); ++ else ++ au_lcnt_dec(&br->br_nfiles); ++ /* note that the file is created and still opened */ ++ ++out: ++ return err; ++} ++ ++int vfsub_kern_path(const char *name, unsigned int flags, struct path *path) ++{ ++ int err; ++ ++ err = kern_path(name, flags, path); ++ if (!err && d_is_positive(path->dentry)) ++ vfsub_update_h_iattr(path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++struct dentry *vfsub_lookup_one_len_unlocked(const char *name, ++ struct path *ppath, int len) ++{ ++ struct path path; ++ ++ path.dentry = lookup_one_len_unlocked(name, ppath->dentry, len); ++ if (IS_ERR(path.dentry)) ++ goto out; ++ if (d_is_positive(path.dentry)) { ++ path.mnt = ppath->mnt; ++ vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/ ++ } ++ ++out: ++ AuTraceErrPtr(path.dentry); ++ return path.dentry; ++} ++ ++struct dentry *vfsub_lookup_one_len(const char *name, struct path *ppath, ++ int len) ++{ ++ struct path path; ++ ++ /* VFS checks it too, but by WARN_ON_ONCE() */ ++ IMustLock(d_inode(ppath->dentry)); ++ ++ path.dentry = lookup_one_len(name, ppath->dentry, len); ++ if (IS_ERR(path.dentry)) ++ goto out; ++ if (d_is_positive(path.dentry)) { ++ path.mnt = ppath->mnt; ++ vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/ ++ } ++ ++out: ++ AuTraceErrPtr(path.dentry); ++ return path.dentry; ++} ++ ++void vfsub_call_lkup_one(void *args) ++{ ++ struct vfsub_lkup_one_args *a = args; ++ *a->errp = vfsub_lkup_one(a->name, a->ppath); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1, ++ struct dentry *d2, struct au_hinode *hdir2) ++{ ++ struct dentry *d; ++ ++ lockdep_off(); ++ d = lock_rename(d1, d2); ++ lockdep_on(); ++ au_hn_suspend(hdir1); ++ if (hdir1 != hdir2) ++ au_hn_suspend(hdir2); ++ ++ return d; ++} ++ ++void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1, ++ struct dentry *d2, struct au_hinode *hdir2) ++{ ++ au_hn_resume(hdir1); ++ if (hdir1 != hdir2) ++ au_hn_resume(hdir2); ++ lockdep_off(); ++ unlock_rename(d1, d2); ++ lockdep_on(); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int vfsub_create(struct inode *dir, struct path *path, int mode, bool want_excl) ++{ ++ int err; ++ struct dentry *d; ++ struct user_namespace *userns; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_mknod(path, d, mode, 0); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ userns = mnt_user_ns(path->mnt); ++ ++ lockdep_off(); ++ err = vfs_create(userns, dir, path->dentry, mode, want_excl); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++int vfsub_symlink(struct inode *dir, struct path *path, const char *symname) ++{ ++ int err; ++ struct dentry *d; ++ struct user_namespace *userns; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_symlink(path, d, symname); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ userns = mnt_user_ns(path->mnt); ++ ++ lockdep_off(); ++ err = vfs_symlink(userns, dir, path->dentry, symname); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev) ++{ ++ int err; ++ struct dentry *d; ++ struct user_namespace *userns; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_mknod(path, d, mode, new_encode_dev(dev)); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ userns = mnt_user_ns(path->mnt); ++ ++ lockdep_off(); ++ err = vfs_mknod(userns, dir, path->dentry, mode, dev); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++static int au_test_nlink(struct inode *inode) ++{ ++ const unsigned int link_max = UINT_MAX >> 1; /* rough margin */ ++ ++ if (!au_test_fs_no_limit_nlink(inode->i_sb) ++ || inode->i_nlink < link_max) ++ return 0; ++ return -EMLINK; ++} ++ ++int vfsub_link(struct dentry *src_dentry, struct inode *dir, struct path *path, ++ struct inode **delegated_inode) ++{ ++ int err; ++ struct dentry *d; ++ struct user_namespace *userns; ++ ++ IMustLock(dir); ++ ++ err = au_test_nlink(d_inode(src_dentry)); ++ if (unlikely(err)) ++ return err; ++ ++ /* we don't call may_linkat() */ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_link(src_dentry, path, d); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ userns = mnt_user_ns(path->mnt); ++ ++ lockdep_off(); ++ err = vfs_link(src_dentry, userns, dir, path->dentry, delegated_inode); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ /* fuse has different memory inode for the same inumber */ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ tmp.dentry = src_dentry; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++int vfsub_rename(struct inode *src_dir, struct dentry *src_dentry, ++ struct inode *dir, struct path *path, ++ struct inode **delegated_inode, unsigned int flags) ++{ ++ int err; ++ struct renamedata rd; ++ struct path tmp = { ++ .mnt = path->mnt ++ }; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ IMustLock(src_dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ tmp.dentry = src_dentry->d_parent; ++ err = security_path_rename(&tmp, src_dentry, path, d, /*flags*/0); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ rd.old_mnt_userns = mnt_user_ns(path->mnt); ++ rd.old_dir = src_dir; ++ rd.old_dentry = src_dentry; ++ rd.new_mnt_userns = rd.old_mnt_userns; ++ rd.new_dir = dir; ++ rd.new_dentry = path->dentry; ++ rd.delegated_inode = delegated_inode; ++ rd.flags = flags; ++ lockdep_off(); ++ err = vfs_rename(&rd); ++ lockdep_on(); ++ if (!err) { ++ int did; ++ ++ tmp.dentry = d->d_parent; ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = src_dentry; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ tmp.dentry = src_dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++int vfsub_mkdir(struct inode *dir, struct path *path, int mode) ++{ ++ int err; ++ struct dentry *d; ++ struct user_namespace *userns; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_mkdir(path, d, mode); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ userns = mnt_user_ns(path->mnt); ++ ++ lockdep_off(); ++ err = vfs_mkdir(userns, dir, path->dentry, mode); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++int vfsub_rmdir(struct inode *dir, struct path *path) ++{ ++ int err; ++ struct dentry *d; ++ struct user_namespace *userns; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_rmdir(path, d); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ userns = mnt_user_ns(path->mnt); ++ ++ lockdep_off(); ++ err = vfs_rmdir(userns, dir, path->dentry); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = { ++ .dentry = path->dentry->d_parent, ++ .mnt = path->mnt ++ }; ++ ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* todo: support mmap_sem? */ ++ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ ++ lockdep_off(); ++ err = vfs_read(file, ubuf, count, ppos); ++ lockdep_on(); ++ if (err >= 0) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ ++ lockdep_off(); ++ err = kernel_read(file, kbuf, count, ppos); ++ lockdep_on(); ++ AuTraceErr(err); ++ if (err >= 0) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ ++ lockdep_off(); ++ err = vfs_write(file, ubuf, count, ppos); ++ lockdep_on(); ++ if (err >= 0) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, loff_t *ppos) ++{ ++ ssize_t err; ++ ++ lockdep_off(); ++ err = kernel_write(file, kbuf, count, ppos); ++ lockdep_on(); ++ if (err >= 0) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++int vfsub_flush(struct file *file, fl_owner_t id) ++{ ++ int err; ++ ++ err = 0; ++ if (file->f_op->flush) { ++ if (!au_test_nfs(file->f_path.dentry->d_sb)) ++ err = file->f_op->flush(file, id); ++ else { ++ lockdep_off(); ++ err = file->f_op->flush(file, id); ++ lockdep_on(); ++ } ++ if (!err) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); ++ /*ignore*/ ++ } ++ return err; ++} ++ ++int vfsub_iterate_dir(struct file *file, struct dir_context *ctx) ++{ ++ int err; ++ ++ AuDbg("%pD, ctx{%ps, %llu}\n", file, ctx->actor, ctx->pos); ++ ++ lockdep_off(); ++ err = iterate_dir(file, ctx); ++ lockdep_on(); ++ if (err >= 0) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ ++ return err; ++} ++ ++long vfsub_splice_to(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags) ++{ ++ long err; ++ ++ lockdep_off(); ++ err = do_splice_to(in, ppos, pipe, len, flags); ++ lockdep_on(); ++ file_accessed(in); ++ if (err >= 0) ++ vfsub_update_h_iattr(&in->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags) ++{ ++ long err; ++ ++ lockdep_off(); ++ err = do_splice_from(pipe, out, ppos, len, flags); ++ lockdep_on(); ++ if (err >= 0) ++ vfsub_update_h_iattr(&out->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++int vfsub_fsync(struct file *file, struct path *path, int datasync) ++{ ++ int err; ++ ++ /* file can be NULL */ ++ lockdep_off(); ++ err = vfs_fsync(file, datasync); ++ lockdep_on(); ++ if (!err) { ++ if (!path) { ++ AuDebugOn(!file); ++ path = &file->f_path; ++ } ++ vfsub_update_h_iattr(path, /*did*/NULL); /*ignore*/ ++ } ++ return err; ++} ++ ++/* cf. open.c:do_sys_truncate() and do_sys_ftruncate() */ ++int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr, ++ struct file *h_file) ++{ ++ int err; ++ struct inode *h_inode; ++ struct super_block *h_sb; ++ struct user_namespace *h_userns; ++ ++ if (!h_file) { ++ err = vfsub_truncate(h_path, length); ++ goto out; ++ } ++ ++ h_inode = d_inode(h_path->dentry); ++ h_sb = h_inode->i_sb; ++ lockdep_off(); ++ sb_start_write(h_sb); ++ lockdep_on(); ++ err = security_path_truncate(h_path); ++ if (!err) { ++ h_userns = mnt_user_ns(h_path->mnt); ++ lockdep_off(); ++ err = do_truncate(h_userns, h_path->dentry, length, attr, ++ h_file); ++ lockdep_on(); ++ } ++ lockdep_off(); ++ sb_end_write(h_sb); ++ lockdep_on(); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_vfsub_mkdir_args { ++ int *errp; ++ struct inode *dir; ++ struct path *path; ++ int mode; ++}; ++ ++static void au_call_vfsub_mkdir(void *args) ++{ ++ struct au_vfsub_mkdir_args *a = args; ++ *a->errp = vfsub_mkdir(a->dir, a->path, a->mode); ++} ++ ++int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode) ++{ ++ int err, do_sio, wkq_err; ++ struct user_namespace *userns; ++ ++ userns = mnt_user_ns(path->mnt); ++ do_sio = au_test_h_perm_sio(userns, dir, MAY_EXEC | MAY_WRITE); ++ if (!do_sio) { ++ lockdep_off(); ++ err = vfsub_mkdir(dir, path, mode); ++ lockdep_on(); ++ } else { ++ struct au_vfsub_mkdir_args args = { ++ .errp = &err, ++ .dir = dir, ++ .path = path, ++ .mode = mode ++ }; ++ wkq_err = au_wkq_wait(au_call_vfsub_mkdir, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ return err; ++} ++ ++struct au_vfsub_rmdir_args { ++ int *errp; ++ struct inode *dir; ++ struct path *path; ++}; ++ ++static void au_call_vfsub_rmdir(void *args) ++{ ++ struct au_vfsub_rmdir_args *a = args; ++ *a->errp = vfsub_rmdir(a->dir, a->path); ++} ++ ++int vfsub_sio_rmdir(struct inode *dir, struct path *path) ++{ ++ int err, do_sio, wkq_err; ++ struct user_namespace *userns; ++ ++ userns = mnt_user_ns(path->mnt); ++ do_sio = au_test_h_perm_sio(userns, dir, MAY_EXEC | MAY_WRITE); ++ if (!do_sio) { ++ lockdep_off(); ++ err = vfsub_rmdir(dir, path); ++ lockdep_on(); ++ } else { ++ struct au_vfsub_rmdir_args args = { ++ .errp = &err, ++ .dir = dir, ++ .path = path ++ }; ++ wkq_err = au_wkq_wait(au_call_vfsub_rmdir, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct notify_change_args { ++ int *errp; ++ struct path *path; ++ struct iattr *ia; ++ struct inode **delegated_inode; ++}; ++ ++static void call_notify_change(void *args) ++{ ++ struct notify_change_args *a = args; ++ struct inode *h_inode; ++ struct user_namespace *userns; ++ ++ h_inode = d_inode(a->path->dentry); ++ IMustLock(h_inode); ++ ++ *a->errp = -EPERM; ++ if (!IS_IMMUTABLE(h_inode) && !IS_APPEND(h_inode)) { ++ userns = mnt_user_ns(a->path->mnt); ++ lockdep_off(); ++ *a->errp = notify_change(userns, a->path->dentry, a->ia, ++ a->delegated_inode); ++ lockdep_on(); ++ if (!*a->errp) ++ vfsub_update_h_iattr(a->path, /*did*/NULL); /*ignore*/ ++ } ++ AuTraceErr(*a->errp); ++} ++ ++int vfsub_notify_change(struct path *path, struct iattr *ia, ++ struct inode **delegated_inode) ++{ ++ int err; ++ struct notify_change_args args = { ++ .errp = &err, ++ .path = path, ++ .ia = ia, ++ .delegated_inode = delegated_inode ++ }; ++ ++ call_notify_change(&args); ++ ++ return err; ++} ++ ++int vfsub_sio_notify_change(struct path *path, struct iattr *ia, ++ struct inode **delegated_inode) ++{ ++ int err, wkq_err; ++ struct notify_change_args args = { ++ .errp = &err, ++ .path = path, ++ .ia = ia, ++ .delegated_inode = delegated_inode ++ }; ++ ++ wkq_err = au_wkq_wait(call_notify_change, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct unlink_args { ++ int *errp; ++ struct inode *dir; ++ struct path *path; ++ struct inode **delegated_inode; ++}; ++ ++static void call_unlink(void *args) ++{ ++ struct unlink_args *a = args; ++ struct dentry *d = a->path->dentry; ++ struct inode *h_inode; ++ struct user_namespace *userns; ++ const int stop_sillyrename = (au_test_nfs(d->d_sb) ++ && au_dcount(d) == 1); ++ ++ IMustLock(a->dir); ++ ++ a->path->dentry = d->d_parent; ++ *a->errp = security_path_unlink(a->path, d); ++ a->path->dentry = d; ++ if (unlikely(*a->errp)) ++ return; ++ ++ if (!stop_sillyrename) ++ dget(d); ++ h_inode = NULL; ++ if (d_is_positive(d)) { ++ h_inode = d_inode(d); ++ ihold(h_inode); ++ } ++ ++ userns = mnt_user_ns(a->path->mnt); ++ lockdep_off(); ++ *a->errp = vfs_unlink(userns, a->dir, d, a->delegated_inode); ++ lockdep_on(); ++ if (!*a->errp) { ++ struct path tmp = { ++ .dentry = d->d_parent, ++ .mnt = a->path->mnt ++ }; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/ ++ } ++ ++ if (!stop_sillyrename) ++ dput(d); ++ if (h_inode) ++ iput(h_inode); ++ ++ AuTraceErr(*a->errp); ++} ++ ++/* ++ * @dir: must be locked. ++ * @dentry: target dentry. ++ */ ++int vfsub_unlink(struct inode *dir, struct path *path, ++ struct inode **delegated_inode, int force) ++{ ++ int err; ++ struct unlink_args args = { ++ .errp = &err, ++ .dir = dir, ++ .path = path, ++ .delegated_inode = delegated_inode ++ }; ++ ++ if (!force) ++ call_unlink(&args); ++ else { ++ int wkq_err; ++ ++ wkq_err = au_wkq_wait(call_unlink, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ return err; ++} +diff -Nurp linux-5.15.37/fs/aufs/vfsub.h linux-5.15.37-aufs/fs/aufs/vfsub.h +--- linux-5.15.37/fs/aufs/vfsub.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/vfsub.h 2022-04-08 20:22:30.616616670 +0300 +@@ -0,0 +1,345 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * sub-routines for VFS ++ */ ++ ++#ifndef __AUFS_VFSUB_H__ ++#define __AUFS_VFSUB_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++#include "debug.h" ++ ++/* copied from linux/fs/internal.h */ ++/* todo: BAD approach!! */ ++extern void __mnt_drop_write(struct vfsmount *); ++extern struct file *alloc_empty_file(int, const struct cred *); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock subclass for lower inode */ ++/* default MAX_LOCKDEP_SUBCLASSES(8) is not enough */ ++/* reduce? gave up. */ ++enum { ++ AuLsc_I_Begin = I_MUTEX_PARENT2, /* 5 */ ++ AuLsc_I_PARENT, /* lower inode, parent first */ ++ AuLsc_I_PARENT2, /* copyup dirs */ ++ AuLsc_I_PARENT3, /* copyup wh */ ++ AuLsc_I_CHILD, ++ AuLsc_I_CHILD2, ++ AuLsc_I_End ++}; ++ ++/* to debug easier, do not make them inlined functions */ ++#define MtxMustLock(mtx) AuDebugOn(!mutex_is_locked(mtx)) ++#define IMustLock(i) AuDebugOn(!inode_is_locked(i)) ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline void vfsub_drop_nlink(struct inode *inode) ++{ ++ AuDebugOn(!inode->i_nlink); ++ drop_nlink(inode); ++} ++ ++static inline void vfsub_dead_dir(struct inode *inode) ++{ ++ AuDebugOn(!S_ISDIR(inode->i_mode)); ++ inode->i_flags |= S_DEAD; ++ clear_nlink(inode); ++} ++ ++static inline int vfsub_native_ro(struct inode *inode) ++{ ++ return sb_rdonly(inode->i_sb) ++ || IS_RDONLY(inode) ++ /* || IS_APPEND(inode) */ ++ || IS_IMMUTABLE(inode); ++} ++ ++#ifdef CONFIG_AUFS_BR_FUSE ++int vfsub_test_mntns(struct vfsmount *mnt, struct super_block *h_sb); ++#else ++AuStubInt0(vfsub_test_mntns, struct vfsmount *mnt, struct super_block *h_sb); ++#endif ++ ++int vfsub_sync_filesystem(struct super_block *h_sb); ++ ++/* ---------------------------------------------------------------------- */ ++ ++int vfsub_update_h_iattr(struct path *h_path, int *did); ++struct file *vfsub_dentry_open(struct path *path, int flags); ++struct file *vfsub_filp_open(const char *path, int oflags, int mode); ++struct au_branch; ++struct vfsub_aopen_args { ++ struct file *file; ++ unsigned int open_flag; ++ umode_t create_mode; ++ struct au_branch *br; ++}; ++int vfsub_atomic_open(struct inode *dir, struct dentry *dentry, ++ struct vfsub_aopen_args *args); ++int vfsub_kern_path(const char *name, unsigned int flags, struct path *path); ++ ++struct dentry *vfsub_lookup_one_len_unlocked(const char *name, ++ struct path *ppath, int len); ++struct dentry *vfsub_lookup_one_len(const char *name, struct path *ppath, ++ int len); ++ ++struct vfsub_lkup_one_args { ++ struct dentry **errp; ++ struct qstr *name; ++ struct path *ppath; ++}; ++ ++static inline struct dentry *vfsub_lkup_one(struct qstr *name, ++ struct path *ppath) ++{ ++ return vfsub_lookup_one_len(name->name, ppath, name->len); ++} ++ ++void vfsub_call_lkup_one(void *args); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline int vfsub_mnt_want_write(struct vfsmount *mnt) ++{ ++ int err; ++ ++ lockdep_off(); ++ err = mnt_want_write(mnt); ++ lockdep_on(); ++ return err; ++} ++ ++static inline void vfsub_mnt_drop_write(struct vfsmount *mnt) ++{ ++ lockdep_off(); ++ mnt_drop_write(mnt); ++ lockdep_on(); ++} ++ ++#if 0 /* reserved */ ++static inline void vfsub_mnt_drop_write_file(struct file *file) ++{ ++ lockdep_off(); ++ mnt_drop_write_file(file); ++ lockdep_on(); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_hinode; ++struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1, ++ struct dentry *d2, struct au_hinode *hdir2); ++void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1, ++ struct dentry *d2, struct au_hinode *hdir2); ++ ++int vfsub_create(struct inode *dir, struct path *path, int mode, ++ bool want_excl); ++int vfsub_symlink(struct inode *dir, struct path *path, ++ const char *symname); ++int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev); ++int vfsub_link(struct dentry *src_dentry, struct inode *dir, ++ struct path *path, struct inode **delegated_inode); ++int vfsub_rename(struct inode *src_hdir, struct dentry *src_dentry, ++ struct inode *hdir, struct path *path, ++ struct inode **delegated_inode, unsigned int flags); ++int vfsub_mkdir(struct inode *dir, struct path *path, int mode); ++int vfsub_rmdir(struct inode *dir, struct path *path); ++ ++/* ---------------------------------------------------------------------- */ ++ ++ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, ++ loff_t *ppos); ++ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, ++ loff_t *ppos); ++ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, ++ loff_t *ppos); ++ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, ++ loff_t *ppos); ++int vfsub_flush(struct file *file, fl_owner_t id); ++int vfsub_iterate_dir(struct file *file, struct dir_context *ctx); ++ ++static inline loff_t vfsub_f_size_read(struct file *file) ++{ ++ return i_size_read(file_inode(file)); ++} ++ ++static inline unsigned int vfsub_file_flags(struct file *file) ++{ ++ unsigned int flags; ++ ++ spin_lock(&file->f_lock); ++ flags = file->f_flags; ++ spin_unlock(&file->f_lock); ++ ++ return flags; ++} ++ ++static inline int vfsub_file_execed(struct file *file) ++{ ++ /* todo: direct access f_flags */ ++ return !!(vfsub_file_flags(file) & __FMODE_EXEC); ++} ++ ++#if 0 /* reserved */ ++static inline void vfsub_file_accessed(struct file *h_file) ++{ ++ file_accessed(h_file); ++ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL); /*ignore*/ ++} ++#endif ++ ++#if 0 /* reserved */ ++static inline void vfsub_touch_atime(struct vfsmount *h_mnt, ++ struct dentry *h_dentry) ++{ ++ struct path h_path = { ++ .dentry = h_dentry, ++ .mnt = h_mnt ++ }; ++ touch_atime(&h_path); ++ vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/ ++} ++#endif ++ ++static inline int vfsub_update_time(struct inode *h_inode, ++ struct timespec64 *ts, int flags) ++{ ++ return inode_update_time(h_inode, ts, flags); ++ /* no vfsub_update_h_iattr() since we don't have struct path */ ++} ++ ++#ifdef CONFIG_FS_POSIX_ACL ++static inline int vfsub_acl_chmod(struct user_namespace *h_userns, ++ struct inode *h_inode, umode_t h_mode) ++{ ++ int err; ++ ++ err = posix_acl_chmod(h_userns, h_inode, h_mode); ++ if (err == -EOPNOTSUPP) ++ err = 0; ++ return err; ++} ++#else ++AuStubInt0(vfsub_acl_chmod, struct user_namespace *h_userns, ++ struct inode *h_inode, umode_t h_mode); ++#endif ++ ++long vfsub_splice_to(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags); ++long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags); ++ ++static inline long vfsub_truncate(struct path *path, loff_t length) ++{ ++ long err; ++ ++ lockdep_off(); ++ err = vfs_truncate(path, length); ++ lockdep_on(); ++ return err; ++} ++ ++int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr, ++ struct file *h_file); ++int vfsub_fsync(struct file *file, struct path *path, int datasync); ++ ++/* ++ * re-use branch fs's ioctl(FICLONE) while aufs itself doesn't support such ++ * ioctl. ++ */ ++static inline loff_t vfsub_clone_file_range(struct file *src, struct file *dst, ++ loff_t len) ++{ ++ loff_t err; ++ ++ lockdep_off(); ++ err = vfs_clone_file_range(src, 0, dst, 0, len, /*remap_flags*/0); ++ lockdep_on(); ++ ++ return err; ++} ++ ++/* copy_file_range(2) is a systemcall */ ++static inline ssize_t vfsub_copy_file_range(struct file *src, loff_t src_pos, ++ struct file *dst, loff_t dst_pos, ++ size_t len, unsigned int flags) ++{ ++ ssize_t ssz; ++ ++ lockdep_off(); ++ ssz = vfs_copy_file_range(src, src_pos, dst, dst_pos, len, flags); ++ lockdep_on(); ++ ++ return ssz; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline loff_t vfsub_llseek(struct file *file, loff_t offset, int origin) ++{ ++ loff_t err; ++ ++ lockdep_off(); ++ err = vfs_llseek(file, offset, origin); ++ lockdep_on(); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode); ++int vfsub_sio_rmdir(struct inode *dir, struct path *path); ++int vfsub_sio_notify_change(struct path *path, struct iattr *ia, ++ struct inode **delegated_inode); ++int vfsub_notify_change(struct path *path, struct iattr *ia, ++ struct inode **delegated_inode); ++int vfsub_unlink(struct inode *dir, struct path *path, ++ struct inode **delegated_inode, int force); ++ ++static inline int vfsub_getattr(const struct path *path, struct kstat *st) ++{ ++ return vfs_getattr(path, st, STATX_BASIC_STATS, AT_STATX_SYNC_AS_STAT); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline int vfsub_setxattr(struct user_namespace *userns, ++ struct dentry *dentry, const char *name, ++ const void *value, size_t size, int flags) ++{ ++ int err; ++ ++ lockdep_off(); ++ err = vfs_setxattr(userns, dentry, name, value, size, flags); ++ lockdep_on(); ++ ++ return err; ++} ++ ++static inline int vfsub_removexattr(struct user_namespace *userns, ++ struct dentry *dentry, const char *name) ++{ ++ int err; ++ ++ lockdep_off(); ++ err = vfs_removexattr(userns, dentry, name); ++ lockdep_on(); ++ ++ return err; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_VFSUB_H__ */ +diff -Nurp linux-5.15.37/fs/aufs/wbr_policy.c linux-5.15.37-aufs/fs/aufs/wbr_policy.c +--- linux-5.15.37/fs/aufs/wbr_policy.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/wbr_policy.c 2022-04-08 20:22:30.616616670 +0300 +@@ -0,0 +1,817 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * policies for selecting one among multiple writable branches ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* subset of cpup_attr() */ ++static noinline_for_stack ++int au_cpdown_attr(struct path *h_path, struct dentry *h_src) ++{ ++ int err, sbits; ++ struct iattr ia; ++ struct inode *h_isrc; ++ ++ h_isrc = d_inode(h_src); ++ ia.ia_valid = ATTR_FORCE | ATTR_MODE | ATTR_UID | ATTR_GID; ++ ia.ia_mode = h_isrc->i_mode; ++ ia.ia_uid = h_isrc->i_uid; ++ ia.ia_gid = h_isrc->i_gid; ++ sbits = !!(ia.ia_mode & (S_ISUID | S_ISGID)); ++ au_cpup_attr_flags(d_inode(h_path->dentry), h_isrc->i_flags); ++ /* no delegation since it is just created */ ++ err = vfsub_sio_notify_change(h_path, &ia, /*delegated*/NULL); ++ ++ /* is this nfs only? */ ++ if (!err && sbits && au_test_nfs(h_path->dentry->d_sb)) { ++ ia.ia_valid = ATTR_FORCE | ATTR_MODE; ++ ia.ia_mode = h_isrc->i_mode; ++ err = vfsub_sio_notify_change(h_path, &ia, /*delegated*/NULL); ++ } ++ ++ return err; ++} ++ ++#define AuCpdown_PARENT_OPQ 1 ++#define AuCpdown_WHED (1 << 1) ++#define AuCpdown_MADE_DIR (1 << 2) ++#define AuCpdown_DIROPQ (1 << 3) ++#define au_ftest_cpdown(flags, name) ((flags) & AuCpdown_##name) ++#define au_fset_cpdown(flags, name) \ ++ do { (flags) |= AuCpdown_##name; } while (0) ++#define au_fclr_cpdown(flags, name) \ ++ do { (flags) &= ~AuCpdown_##name; } while (0) ++ ++static int au_cpdown_dir_opq(struct dentry *dentry, aufs_bindex_t bdst, ++ unsigned int *flags) ++{ ++ int err; ++ struct dentry *opq_dentry; ++ ++ opq_dentry = au_diropq_create(dentry, bdst); ++ err = PTR_ERR(opq_dentry); ++ if (IS_ERR(opq_dentry)) ++ goto out; ++ dput(opq_dentry); ++ au_fset_cpdown(*flags, DIROPQ); ++ ++out: ++ return err; ++} ++ ++static int au_cpdown_dir_wh(struct dentry *dentry, struct dentry *h_parent, ++ struct inode *dir, aufs_bindex_t bdst) ++{ ++ int err; ++ struct path h_path; ++ struct au_branch *br; ++ ++ br = au_sbr(dentry->d_sb, bdst); ++ h_path.dentry = au_wh_lkup(h_parent, &dentry->d_name, br); ++ err = PTR_ERR(h_path.dentry); ++ if (IS_ERR(h_path.dentry)) ++ goto out; ++ ++ err = 0; ++ if (d_is_positive(h_path.dentry)) { ++ h_path.mnt = au_br_mnt(br); ++ err = au_wh_unlink_dentry(au_h_iptr(dir, bdst), &h_path, ++ dentry); ++ } ++ dput(h_path.dentry); ++ ++out: ++ return err; ++} ++ ++static int au_cpdown_dir(struct dentry *dentry, aufs_bindex_t bdst, ++ struct au_pin *pin, ++ struct dentry *h_parent, void *arg) ++{ ++ int err, rerr; ++ aufs_bindex_t bopq, btop; ++ struct path h_path; ++ struct dentry *parent; ++ struct inode *h_dir, *h_inode, *inode, *dir; ++ unsigned int *flags = arg; ++ ++ btop = au_dbtop(dentry); ++ /* dentry is di-locked */ ++ parent = dget_parent(dentry); ++ dir = d_inode(parent); ++ h_dir = d_inode(h_parent); ++ AuDebugOn(h_dir != au_h_iptr(dir, bdst)); ++ IMustLock(h_dir); ++ ++ err = au_lkup_neg(dentry, bdst, /*wh*/0); ++ if (unlikely(err < 0)) ++ goto out; ++ h_path.dentry = au_h_dptr(dentry, bdst); ++ h_path.mnt = au_sbr_mnt(dentry->d_sb, bdst); ++ err = vfsub_sio_mkdir(au_h_iptr(dir, bdst), &h_path, 0755); ++ if (unlikely(err)) ++ goto out_put; ++ au_fset_cpdown(*flags, MADE_DIR); ++ ++ bopq = au_dbdiropq(dentry); ++ au_fclr_cpdown(*flags, WHED); ++ au_fclr_cpdown(*flags, DIROPQ); ++ if (au_dbwh(dentry) == bdst) ++ au_fset_cpdown(*flags, WHED); ++ if (!au_ftest_cpdown(*flags, PARENT_OPQ) && bopq <= bdst) ++ au_fset_cpdown(*flags, PARENT_OPQ); ++ h_inode = d_inode(h_path.dentry); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ if (au_ftest_cpdown(*flags, WHED)) { ++ err = au_cpdown_dir_opq(dentry, bdst, flags); ++ if (unlikely(err)) { ++ inode_unlock(h_inode); ++ goto out_dir; ++ } ++ } ++ ++ err = au_cpdown_attr(&h_path, au_h_dptr(dentry, btop)); ++ inode_unlock(h_inode); ++ if (unlikely(err)) ++ goto out_opq; ++ ++ if (au_ftest_cpdown(*flags, WHED)) { ++ err = au_cpdown_dir_wh(dentry, h_parent, dir, bdst); ++ if (unlikely(err)) ++ goto out_opq; ++ } ++ ++ inode = d_inode(dentry); ++ if (au_ibbot(inode) < bdst) ++ au_set_ibbot(inode, bdst); ++ au_set_h_iptr(inode, bdst, au_igrab(h_inode), ++ au_hi_flags(inode, /*isdir*/1)); ++ au_fhsm_wrote(dentry->d_sb, bdst, /*force*/0); ++ goto out; /* success */ ++ ++ /* revert */ ++out_opq: ++ if (au_ftest_cpdown(*flags, DIROPQ)) { ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ rerr = au_diropq_remove(dentry, bdst); ++ inode_unlock(h_inode); ++ if (unlikely(rerr)) { ++ AuIOErr("failed removing diropq for %pd b%d (%d)\n", ++ dentry, bdst, rerr); ++ err = -EIO; ++ goto out; ++ } ++ } ++out_dir: ++ if (au_ftest_cpdown(*flags, MADE_DIR)) { ++ rerr = vfsub_sio_rmdir(au_h_iptr(dir, bdst), &h_path); ++ if (unlikely(rerr)) { ++ AuIOErr("failed removing %pd b%d (%d)\n", ++ dentry, bdst, rerr); ++ err = -EIO; ++ } ++ } ++out_put: ++ au_set_h_dptr(dentry, bdst, NULL); ++ if (au_dbbot(dentry) == bdst) ++ au_update_dbbot(dentry); ++out: ++ dput(parent); ++ return err; ++} ++ ++int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst) ++{ ++ int err; ++ unsigned int flags; ++ ++ flags = 0; ++ err = au_cp_dirs(dentry, bdst, au_cpdown_dir, &flags); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policies for create */ ++ ++int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ int err, i, j, ndentry; ++ aufs_bindex_t bopq; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries, *parent, *d; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ parent = dget_parent(dentry); ++ err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/0); ++ if (unlikely(err)) ++ goto out_free; ++ ++ err = bindex; ++ for (i = 0; i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ ndentry = dpage->ndentry; ++ for (j = 0; j < ndentry; j++) { ++ d = dentries[j]; ++ di_read_lock_parent2(d, !AuLock_IR); ++ bopq = au_dbdiropq(d); ++ di_read_unlock(d, !AuLock_IR); ++ if (bopq >= 0 && bopq < err) ++ err = bopq; ++ } ++ } ++ ++out_free: ++ dput(parent); ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++static int au_wbr_bu(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ for (; bindex >= 0; bindex--) ++ if (!au_br_rdonly(au_sbr(sb, bindex))) ++ return bindex; ++ return -EROFS; ++} ++ ++/* top down parent */ ++static int au_wbr_create_tdp(struct dentry *dentry, ++ unsigned int flags __maybe_unused) ++{ ++ int err; ++ aufs_bindex_t btop, bindex; ++ struct super_block *sb; ++ struct dentry *parent, *h_parent; ++ ++ sb = dentry->d_sb; ++ btop = au_dbtop(dentry); ++ err = btop; ++ if (!au_br_rdonly(au_sbr(sb, btop))) ++ goto out; ++ ++ err = -EROFS; ++ parent = dget_parent(dentry); ++ for (bindex = au_dbtop(parent); bindex < btop; bindex++) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || d_is_negative(h_parent)) ++ continue; ++ ++ if (!au_br_rdonly(au_sbr(sb, bindex))) { ++ err = bindex; ++ break; ++ } ++ } ++ dput(parent); ++ ++ /* bottom up here */ ++ if (unlikely(err < 0)) { ++ err = au_wbr_bu(sb, btop - 1); ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ } ++ ++out: ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* an exception for the policy other than tdp */ ++static int au_wbr_create_exp(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t bwh, bdiropq; ++ struct dentry *parent; ++ ++ err = -1; ++ bwh = au_dbwh(dentry); ++ parent = dget_parent(dentry); ++ bdiropq = au_dbdiropq(parent); ++ if (bwh >= 0) { ++ if (bdiropq >= 0) ++ err = min(bdiropq, bwh); ++ else ++ err = bwh; ++ AuDbg("%d\n", err); ++ } else if (bdiropq >= 0) { ++ err = bdiropq; ++ AuDbg("%d\n", err); ++ } ++ dput(parent); ++ ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ ++ if (err >= 0 && au_br_rdonly(au_sbr(dentry->d_sb, err))) ++ err = -1; ++ ++ AuDbg("%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* round robin */ ++static int au_wbr_create_init_rr(struct super_block *sb) ++{ ++ int err; ++ ++ err = au_wbr_bu(sb, au_sbbot(sb)); ++ atomic_set(&au_sbi(sb)->si_wbr_rr_next, -err); /* less important */ ++ /* smp_mb(); */ ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_create_rr(struct dentry *dentry, unsigned int flags) ++{ ++ int err, nbr; ++ unsigned int u; ++ aufs_bindex_t bindex, bbot; ++ struct super_block *sb; ++ atomic_t *next; ++ ++ err = au_wbr_create_exp(dentry); ++ if (err >= 0) ++ goto out; ++ ++ sb = dentry->d_sb; ++ next = &au_sbi(sb)->si_wbr_rr_next; ++ bbot = au_sbbot(sb); ++ nbr = bbot + 1; ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ if (!au_ftest_wbr(flags, DIR)) { ++ err = atomic_dec_return(next) + 1; ++ /* modulo for 0 is meaningless */ ++ if (unlikely(!err)) ++ err = atomic_dec_return(next) + 1; ++ } else ++ err = atomic_read(next); ++ AuDbg("%d\n", err); ++ u = err; ++ err = u % nbr; ++ AuDbg("%d\n", err); ++ if (!au_br_rdonly(au_sbr(sb, err))) ++ break; ++ err = -EROFS; ++ } ++ ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ ++out: ++ AuDbg("%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* most free space */ ++static void au_mfs(struct dentry *dentry, struct dentry *parent) ++{ ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_wbr_mfs *mfs; ++ struct dentry *h_parent; ++ aufs_bindex_t bindex, bbot; ++ int err; ++ unsigned long long b, bavail; ++ struct path h_path; ++ /* reduce the stack usage */ ++ struct kstatfs *st; ++ ++ st = kmalloc(sizeof(*st), GFP_NOFS); ++ if (unlikely(!st)) { ++ AuWarn1("failed updating mfs(%d), ignored\n", -ENOMEM); ++ return; ++ } ++ ++ bavail = 0; ++ sb = dentry->d_sb; ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ MtxMustLock(&mfs->mfs_lock); ++ mfs->mfs_bindex = -EROFS; ++ mfs->mfsrr_bytes = 0; ++ if (!parent) { ++ bindex = 0; ++ bbot = au_sbbot(sb); ++ } else { ++ bindex = au_dbtop(parent); ++ bbot = au_dbtaildir(parent); ++ } ++ ++ for (; bindex <= bbot; bindex++) { ++ if (parent) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || d_is_negative(h_parent)) ++ continue; ++ } ++ br = au_sbr(sb, bindex); ++ if (au_br_rdonly(br)) ++ continue; ++ ++ /* sb->s_root for NFS is unreliable */ ++ h_path.mnt = au_br_mnt(br); ++ h_path.dentry = h_path.mnt->mnt_root; ++ err = vfs_statfs(&h_path, st); ++ if (unlikely(err)) { ++ AuWarn1("failed statfs, b%d, %d\n", bindex, err); ++ continue; ++ } ++ ++ /* when the available size is equal, select the lower one */ ++ BUILD_BUG_ON(sizeof(b) < sizeof(st->f_bavail) ++ || sizeof(b) < sizeof(st->f_bsize)); ++ b = st->f_bavail * st->f_bsize; ++ br->br_wbr->wbr_bytes = b; ++ if (b >= bavail) { ++ bavail = b; ++ mfs->mfs_bindex = bindex; ++ mfs->mfs_jiffy = jiffies; ++ } ++ } ++ ++ mfs->mfsrr_bytes = bavail; ++ AuDbg("b%d\n", mfs->mfs_bindex); ++ au_kfree_rcu(st); ++} ++ ++static int au_wbr_create_mfs(struct dentry *dentry, unsigned int flags) ++{ ++ int err; ++ struct dentry *parent; ++ struct super_block *sb; ++ struct au_wbr_mfs *mfs; ++ ++ err = au_wbr_create_exp(dentry); ++ if (err >= 0) ++ goto out; ++ ++ sb = dentry->d_sb; ++ parent = NULL; ++ if (au_ftest_wbr(flags, PARENT)) ++ parent = dget_parent(dentry); ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ mutex_lock(&mfs->mfs_lock); ++ if (time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire) ++ || mfs->mfs_bindex < 0 ++ || au_br_rdonly(au_sbr(sb, mfs->mfs_bindex))) ++ au_mfs(dentry, parent); ++ mutex_unlock(&mfs->mfs_lock); ++ err = mfs->mfs_bindex; ++ dput(parent); ++ ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ ++out: ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_create_init_mfs(struct super_block *sb) ++{ ++ struct au_wbr_mfs *mfs; ++ ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ mutex_init(&mfs->mfs_lock); ++ mfs->mfs_jiffy = 0; ++ mfs->mfs_bindex = -EROFS; ++ ++ return 0; ++} ++ ++static int au_wbr_create_fin_mfs(struct super_block *sb __maybe_unused) ++{ ++ mutex_destroy(&au_sbi(sb)->si_wbr_mfs.mfs_lock); ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* top down regardless parent, and then mfs */ ++static int au_wbr_create_tdmfs(struct dentry *dentry, ++ unsigned int flags __maybe_unused) ++{ ++ int err; ++ aufs_bindex_t bwh, btail, bindex, bfound, bmfs; ++ unsigned long long watermark; ++ struct super_block *sb; ++ struct au_wbr_mfs *mfs; ++ struct au_branch *br; ++ struct dentry *parent; ++ ++ sb = dentry->d_sb; ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ mutex_lock(&mfs->mfs_lock); ++ if (time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire) ++ || mfs->mfs_bindex < 0) ++ au_mfs(dentry, /*parent*/NULL); ++ watermark = mfs->mfsrr_watermark; ++ bmfs = mfs->mfs_bindex; ++ mutex_unlock(&mfs->mfs_lock); ++ ++ /* another style of au_wbr_create_exp() */ ++ bwh = au_dbwh(dentry); ++ parent = dget_parent(dentry); ++ btail = au_dbtaildir(parent); ++ if (bwh >= 0 && bwh < btail) ++ btail = bwh; ++ ++ err = au_wbr_nonopq(dentry, btail); ++ if (unlikely(err < 0)) ++ goto out; ++ btail = err; ++ bfound = -1; ++ for (bindex = 0; bindex <= btail; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_rdonly(br)) ++ continue; ++ if (br->br_wbr->wbr_bytes > watermark) { ++ bfound = bindex; ++ break; ++ } ++ } ++ err = bfound; ++ if (err < 0) ++ err = bmfs; ++ ++out: ++ dput(parent); ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* most free space and then round robin */ ++static int au_wbr_create_mfsrr(struct dentry *dentry, unsigned int flags) ++{ ++ int err; ++ struct au_wbr_mfs *mfs; ++ ++ err = au_wbr_create_mfs(dentry, flags); ++ if (err >= 0) { ++ mfs = &au_sbi(dentry->d_sb)->si_wbr_mfs; ++ mutex_lock(&mfs->mfs_lock); ++ if (mfs->mfsrr_bytes < mfs->mfsrr_watermark) ++ err = au_wbr_create_rr(dentry, flags); ++ mutex_unlock(&mfs->mfs_lock); ++ } ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_create_init_mfsrr(struct super_block *sb) ++{ ++ int err; ++ ++ au_wbr_create_init_mfs(sb); /* ignore */ ++ err = au_wbr_create_init_rr(sb); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* top down parent and most free space */ ++static int au_wbr_create_pmfs(struct dentry *dentry, unsigned int flags) ++{ ++ int err, e2; ++ unsigned long long b; ++ aufs_bindex_t bindex, btop, bbot; ++ struct super_block *sb; ++ struct dentry *parent, *h_parent; ++ struct au_branch *br; ++ ++ err = au_wbr_create_tdp(dentry, flags); ++ if (unlikely(err < 0)) ++ goto out; ++ parent = dget_parent(dentry); ++ btop = au_dbtop(parent); ++ bbot = au_dbtaildir(parent); ++ if (btop == bbot) ++ goto out_parent; /* success */ ++ ++ e2 = au_wbr_create_mfs(dentry, flags); ++ if (e2 < 0) ++ goto out_parent; /* success */ ++ ++ /* when the available size is equal, select upper one */ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, err); ++ b = br->br_wbr->wbr_bytes; ++ AuDbg("b%d, %llu\n", err, b); ++ ++ for (bindex = btop; bindex <= bbot; bindex++) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || d_is_negative(h_parent)) ++ continue; ++ ++ br = au_sbr(sb, bindex); ++ if (!au_br_rdonly(br) && br->br_wbr->wbr_bytes > b) { ++ b = br->br_wbr->wbr_bytes; ++ err = bindex; ++ AuDbg("b%d, %llu\n", err, b); ++ } ++ } ++ ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ ++out_parent: ++ dput(parent); ++out: ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * - top down parent ++ * - most free space with parent ++ * - most free space round-robin regardless parent ++ */ ++static int au_wbr_create_pmfsrr(struct dentry *dentry, unsigned int flags) ++{ ++ int err; ++ unsigned long long watermark; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_wbr_mfs *mfs; ++ ++ err = au_wbr_create_pmfs(dentry, flags | AuWbr_PARENT); ++ if (unlikely(err < 0)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, err); ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ mutex_lock(&mfs->mfs_lock); ++ watermark = mfs->mfsrr_watermark; ++ mutex_unlock(&mfs->mfs_lock); ++ if (br->br_wbr->wbr_bytes < watermark) ++ /* regardless the parent dir */ ++ err = au_wbr_create_mfsrr(dentry, flags); ++ ++out: ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policies for copyup */ ++ ++/* top down parent */ ++static int au_wbr_copyup_tdp(struct dentry *dentry) ++{ ++ return au_wbr_create_tdp(dentry, /*flags, anything is ok*/0); ++} ++ ++/* bottom up parent */ ++static int au_wbr_copyup_bup(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t bindex, btop; ++ struct dentry *parent, *h_parent; ++ struct super_block *sb; ++ ++ err = -EROFS; ++ sb = dentry->d_sb; ++ parent = dget_parent(dentry); ++ btop = au_dbtop(parent); ++ for (bindex = au_dbtop(dentry); bindex >= btop; bindex--) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || d_is_negative(h_parent)) ++ continue; ++ ++ if (!au_br_rdonly(au_sbr(sb, bindex))) { ++ err = bindex; ++ break; ++ } ++ } ++ dput(parent); ++ ++ /* bottom up here */ ++ if (unlikely(err < 0)) ++ err = au_wbr_bu(sb, btop - 1); ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* bottom up */ ++int au_wbr_do_copyup_bu(struct dentry *dentry, aufs_bindex_t btop) ++{ ++ int err; ++ ++ err = au_wbr_bu(dentry->d_sb, btop); ++ AuDbg("b%d\n", err); ++ if (err > btop) ++ err = au_wbr_nonopq(dentry, err); ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_copyup_bu(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t btop; ++ ++ btop = au_dbtop(dentry); ++ err = au_wbr_do_copyup_bu(dentry, btop); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_wbr_copyup_operations au_wbr_copyup_ops[] = { ++ [AuWbrCopyup_TDP] = { ++ .copyup = au_wbr_copyup_tdp ++ }, ++ [AuWbrCopyup_BUP] = { ++ .copyup = au_wbr_copyup_bup ++ }, ++ [AuWbrCopyup_BU] = { ++ .copyup = au_wbr_copyup_bu ++ } ++}; ++ ++struct au_wbr_create_operations au_wbr_create_ops[] = { ++ [AuWbrCreate_TDP] = { ++ .create = au_wbr_create_tdp ++ }, ++ [AuWbrCreate_RR] = { ++ .create = au_wbr_create_rr, ++ .init = au_wbr_create_init_rr ++ }, ++ [AuWbrCreate_MFS] = { ++ .create = au_wbr_create_mfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_MFSV] = { ++ .create = au_wbr_create_mfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_MFSRR] = { ++ .create = au_wbr_create_mfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_MFSRRV] = { ++ .create = au_wbr_create_mfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_TDMFS] = { ++ .create = au_wbr_create_tdmfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_TDMFSV] = { ++ .create = au_wbr_create_tdmfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_PMFS] = { ++ .create = au_wbr_create_pmfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_PMFSV] = { ++ .create = au_wbr_create_pmfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_PMFSRR] = { ++ .create = au_wbr_create_pmfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_PMFSRRV] = { ++ .create = au_wbr_create_pmfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ } ++}; +diff -Nurp linux-5.15.37/fs/aufs/whout.c linux-5.15.37-aufs/fs/aufs/whout.c +--- linux-5.15.37/fs/aufs/whout.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/whout.c 2022-04-08 20:22:30.616616670 +0300 +@@ -0,0 +1,1059 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * whiteout for logical deletion and opaque directory ++ */ ++ ++#include "aufs.h" ++ ++#define WH_MASK 0444 ++ ++/* ++ * If a directory contains this file, then it is opaque. We start with the ++ * .wh. flag so that it is blocked by lookup. ++ */ ++static struct qstr diropq_name = QSTR_INIT(AUFS_WH_DIROPQ, ++ sizeof(AUFS_WH_DIROPQ) - 1); ++ ++/* ++ * generate whiteout name, which is NOT terminated by NULL. ++ * @name: original d_name.name ++ * @len: original d_name.len ++ * @wh: whiteout qstr ++ * returns zero when succeeds, otherwise error. ++ * succeeded value as wh->name should be freed by kfree(). ++ */ ++int au_wh_name_alloc(struct qstr *wh, const struct qstr *name) ++{ ++ char *p; ++ ++ if (unlikely(name->len > PATH_MAX - AUFS_WH_PFX_LEN)) ++ return -ENAMETOOLONG; ++ ++ wh->len = name->len + AUFS_WH_PFX_LEN; ++ p = kmalloc(wh->len, GFP_NOFS); ++ wh->name = p; ++ if (p) { ++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); ++ memcpy(p + AUFS_WH_PFX_LEN, name->name, name->len); ++ /* smp_mb(); */ ++ return 0; ++ } ++ return -ENOMEM; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * test if the @wh_name exists under @h_ppath. ++ * @try_sio specifies the necessary of super-io. ++ */ ++int au_wh_test(struct user_namespace *h_userns, struct path *h_ppath, ++ struct qstr *wh_name, int try_sio) ++{ ++ int err; ++ struct dentry *wh_dentry; ++ ++ if (!try_sio) ++ wh_dentry = vfsub_lkup_one(wh_name, h_ppath); ++ else ++ wh_dentry = au_sio_lkup_one(h_userns, wh_name, h_ppath); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) { ++ if (err == -ENAMETOOLONG) ++ err = 0; ++ goto out; ++ } ++ ++ err = 0; ++ if (d_is_negative(wh_dentry)) ++ goto out_wh; /* success */ ++ ++ err = 1; ++ if (d_is_reg(wh_dentry)) ++ goto out_wh; /* success */ ++ ++ err = -EIO; ++ AuIOErr("%pd Invalid whiteout entry type 0%o.\n", ++ wh_dentry, d_inode(wh_dentry)->i_mode); ++ ++out_wh: ++ dput(wh_dentry); ++out: ++ return err; ++} ++ ++/* ++ * test if the @h_path->dentry sets opaque or not. ++ */ ++int au_diropq_test(struct user_namespace *h_userns, struct path *h_path) ++{ ++ int err; ++ struct inode *h_dir; ++ ++ h_dir = d_inode(h_path->dentry); ++ err = au_wh_test(h_userns, h_path, &diropq_name, ++ au_test_h_perm_sio(h_userns, h_dir, MAY_EXEC)); ++ return err; ++} ++ ++/* ++ * returns a negative dentry whose name is unique and temporary. ++ */ ++struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br, ++ struct qstr *prefix) ++{ ++ struct dentry *dentry; ++ int i; ++ char defname[NAME_MAX - AUFS_MAX_NAMELEN + DNAME_INLINE_LEN + 1], ++ *name, *p; ++ /* strict atomic_t is unnecessary here */ ++ static unsigned short cnt; ++ struct qstr qs; ++ struct path h_ppath; ++ struct user_namespace *h_userns; ++ ++ BUILD_BUG_ON(sizeof(cnt) * 2 > AUFS_WH_TMP_LEN); ++ ++ name = defname; ++ qs.len = sizeof(defname) - DNAME_INLINE_LEN + prefix->len - 1; ++ if (unlikely(prefix->len > DNAME_INLINE_LEN)) { ++ dentry = ERR_PTR(-ENAMETOOLONG); ++ if (unlikely(qs.len > NAME_MAX)) ++ goto out; ++ dentry = ERR_PTR(-ENOMEM); ++ name = kmalloc(qs.len + 1, GFP_NOFS); ++ if (unlikely(!name)) ++ goto out; ++ } ++ ++ /* doubly whiteout-ed */ ++ memcpy(name, AUFS_WH_PFX AUFS_WH_PFX, AUFS_WH_PFX_LEN * 2); ++ p = name + AUFS_WH_PFX_LEN * 2; ++ memcpy(p, prefix->name, prefix->len); ++ p += prefix->len; ++ *p++ = '.'; ++ AuDebugOn(name + qs.len + 1 - p <= AUFS_WH_TMP_LEN); ++ ++ h_ppath.dentry = h_parent; ++ h_ppath.mnt = au_br_mnt(br); ++ h_userns = au_br_userns(br); ++ qs.name = name; ++ for (i = 0; i < 3; i++) { ++ sprintf(p, "%.*x", AUFS_WH_TMP_LEN, cnt++); ++ dentry = au_sio_lkup_one(h_userns, &qs, &h_ppath); ++ if (IS_ERR(dentry) || d_is_negative(dentry)) ++ goto out_name; ++ dput(dentry); ++ } ++ /* pr_warn("could not get random name\n"); */ ++ dentry = ERR_PTR(-EEXIST); ++ AuDbg("%.*s\n", AuLNPair(&qs)); ++ BUG(); ++ ++out_name: ++ if (name != defname) ++ au_kfree_try_rcu(name); ++out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ++ * rename the @h_dentry on @br to the whiteouted temporary name. ++ */ ++int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br) ++{ ++ int err; ++ struct path h_path = { ++ .mnt = au_br_mnt(br) ++ }; ++ struct inode *h_dir, *delegated; ++ struct dentry *h_parent; ++ ++ h_parent = h_dentry->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ ++ h_path.dentry = au_whtmp_lkup(h_parent, br, &h_dentry->d_name); ++ err = PTR_ERR(h_path.dentry); ++ if (IS_ERR(h_path.dentry)) ++ goto out; ++ ++ /* under the same dir, no need to lock_rename() */ ++ delegated = NULL; ++ err = vfsub_rename(h_dir, h_dentry, h_dir, &h_path, &delegated, ++ /*flags*/0); ++ AuTraceErr(err); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ dput(h_path.dentry); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * functions for removing a whiteout ++ */ ++ ++static int do_unlink_wh(struct inode *h_dir, struct path *h_path) ++{ ++ int err, force; ++ struct inode *delegated; ++ ++ /* ++ * forces superio when the dir has a sticky bit. ++ * this may be a violation of unix fs semantics. ++ */ ++ force = (h_dir->i_mode & S_ISVTX) ++ && !uid_eq(current_fsuid(), d_inode(h_path->dentry)->i_uid); ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, h_path, &delegated, force); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ return err; ++} ++ ++int au_wh_unlink_dentry(struct inode *h_dir, struct path *h_path, ++ struct dentry *dentry) ++{ ++ int err; ++ ++ err = do_unlink_wh(h_dir, h_path); ++ if (!err && dentry) ++ au_set_dbwh(dentry, -1); ++ ++ return err; ++} ++ ++static int unlink_wh_name(struct path *h_ppath, struct qstr *wh) ++{ ++ int err; ++ struct path h_path; ++ ++ err = 0; ++ h_path.dentry = vfsub_lkup_one(wh, h_ppath); ++ if (IS_ERR(h_path.dentry)) ++ err = PTR_ERR(h_path.dentry); ++ else { ++ if (d_is_reg(h_path.dentry)) { ++ h_path.mnt = h_ppath->mnt; ++ err = do_unlink_wh(d_inode(h_ppath->dentry), &h_path); ++ } ++ dput(h_path.dentry); ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * initialize/clean whiteout for a branch ++ */ ++ ++static void au_wh_clean(struct inode *h_dir, struct path *whpath, ++ const int isdir) ++{ ++ int err; ++ struct inode *delegated; ++ ++ if (d_is_negative(whpath->dentry)) ++ return; ++ ++ if (isdir) ++ err = vfsub_rmdir(h_dir, whpath); ++ else { ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, whpath, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ } ++ if (unlikely(err)) ++ pr_warn("failed removing %pd (%d), ignored.\n", ++ whpath->dentry, err); ++} ++ ++static int test_linkable(struct dentry *h_root) ++{ ++ struct inode *h_dir = d_inode(h_root); ++ ++ if (h_dir->i_op->link) ++ return 0; ++ ++ pr_err("%pd (%s) doesn't support link(2), use noplink and rw+nolwh\n", ++ h_root, au_sbtype(h_root->d_sb)); ++ return -ENOSYS; /* the branch doesn't have its ->link() */ ++} ++ ++/* todo: should this mkdir be done in /sbin/mount.aufs helper? */ ++static int au_whdir(struct inode *h_dir, struct path *path) ++{ ++ int err; ++ ++ err = -EEXIST; ++ if (d_is_negative(path->dentry)) { ++ int mode = 0700; ++ ++ if (au_test_nfs(path->dentry->d_sb)) ++ mode |= 0111; ++ err = vfsub_mkdir(h_dir, path, mode); ++ } else if (d_is_dir(path->dentry)) ++ err = 0; ++ else ++ pr_err("unknown %pd exists\n", path->dentry); ++ ++ return err; ++} ++ ++struct au_wh_base { ++ const struct qstr *name; ++ struct dentry *dentry; ++}; ++ ++static void au_wh_init_ro(struct inode *h_dir, struct au_wh_base base[], ++ struct path *h_path) ++{ ++ h_path->dentry = base[AuBrWh_BASE].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/0); ++ h_path->dentry = base[AuBrWh_PLINK].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++ h_path->dentry = base[AuBrWh_ORPH].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++} ++ ++/* ++ * returns tri-state, ++ * minus: error, caller should print the message ++ * zero: success ++ * plus: error, caller should NOT print the message ++ */ ++static int au_wh_init_rw_nolink(struct dentry *h_root, struct au_wbr *wbr, ++ int do_plink, struct au_wh_base base[], ++ struct path *h_path) ++{ ++ int err; ++ struct inode *h_dir; ++ ++ h_dir = d_inode(h_root); ++ h_path->dentry = base[AuBrWh_BASE].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/0); ++ h_path->dentry = base[AuBrWh_PLINK].dentry; ++ if (do_plink) { ++ err = test_linkable(h_root); ++ if (unlikely(err)) { ++ err = 1; ++ goto out; ++ } ++ ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry); ++ } else ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++ h_path->dentry = base[AuBrWh_ORPH].dentry; ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry); ++ ++out: ++ return err; ++} ++ ++/* ++ * for the moment, aufs supports the branch filesystem which does not support ++ * link(2). testing on FAT which does not support i_op->setattr() fully either, ++ * copyup failed. finally, such filesystem will not be used as the writable ++ * branch. ++ * ++ * returns tri-state, see above. ++ */ ++static int au_wh_init_rw(struct dentry *h_root, struct au_wbr *wbr, ++ int do_plink, struct au_wh_base base[], ++ struct path *h_path) ++{ ++ int err; ++ struct inode *h_dir; ++ ++ WbrWhMustWriteLock(wbr); ++ ++ err = test_linkable(h_root); ++ if (unlikely(err)) { ++ err = 1; ++ goto out; ++ } ++ ++ /* ++ * todo: should this create be done in /sbin/mount.aufs helper? ++ */ ++ err = -EEXIST; ++ h_dir = d_inode(h_root); ++ if (d_is_negative(base[AuBrWh_BASE].dentry)) { ++ h_path->dentry = base[AuBrWh_BASE].dentry; ++ err = vfsub_create(h_dir, h_path, WH_MASK, /*want_excl*/true); ++ } else if (d_is_reg(base[AuBrWh_BASE].dentry)) ++ err = 0; ++ else ++ pr_err("unknown %pd2 exists\n", base[AuBrWh_BASE].dentry); ++ if (unlikely(err)) ++ goto out; ++ ++ h_path->dentry = base[AuBrWh_PLINK].dentry; ++ if (do_plink) { ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry); ++ } else ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++ wbr->wbr_whbase = dget(base[AuBrWh_BASE].dentry); ++ ++ h_path->dentry = base[AuBrWh_ORPH].dentry; ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry); ++ ++out: ++ return err; ++} ++ ++/* ++ * initialize the whiteout base file/dir for @br. ++ */ ++int au_wh_init(struct au_branch *br, struct super_block *sb) ++{ ++ int err, i; ++ const unsigned char do_plink ++ = !!au_opt_test(au_mntflags(sb), PLINK); ++ struct inode *h_dir; ++ struct path path = br->br_path; ++ struct dentry *h_root = path.dentry; ++ struct au_wbr *wbr = br->br_wbr; ++ static const struct qstr base_name[] = { ++ [AuBrWh_BASE] = QSTR_INIT(AUFS_BASE_NAME, ++ sizeof(AUFS_BASE_NAME) - 1), ++ [AuBrWh_PLINK] = QSTR_INIT(AUFS_PLINKDIR_NAME, ++ sizeof(AUFS_PLINKDIR_NAME) - 1), ++ [AuBrWh_ORPH] = QSTR_INIT(AUFS_ORPHDIR_NAME, ++ sizeof(AUFS_ORPHDIR_NAME) - 1) ++ }; ++ struct au_wh_base base[] = { ++ [AuBrWh_BASE] = { ++ .name = base_name + AuBrWh_BASE, ++ .dentry = NULL ++ }, ++ [AuBrWh_PLINK] = { ++ .name = base_name + AuBrWh_PLINK, ++ .dentry = NULL ++ }, ++ [AuBrWh_ORPH] = { ++ .name = base_name + AuBrWh_ORPH, ++ .dentry = NULL ++ } ++ }; ++ ++ if (wbr) ++ WbrWhMustWriteLock(wbr); ++ ++ for (i = 0; i < AuBrWh_Last; i++) { ++ /* doubly whiteouted */ ++ struct dentry *d; ++ ++ d = au_wh_lkup(h_root, (void *)base[i].name, br); ++ err = PTR_ERR(d); ++ if (IS_ERR(d)) ++ goto out; ++ ++ base[i].dentry = d; ++ AuDebugOn(wbr ++ && wbr->wbr_wh[i] ++ && wbr->wbr_wh[i] != base[i].dentry); ++ } ++ ++ if (wbr) ++ for (i = 0; i < AuBrWh_Last; i++) { ++ dput(wbr->wbr_wh[i]); ++ wbr->wbr_wh[i] = NULL; ++ } ++ ++ err = 0; ++ if (!au_br_writable(br->br_perm)) { ++ h_dir = d_inode(h_root); ++ au_wh_init_ro(h_dir, base, &path); ++ } else if (!au_br_wh_linkable(br->br_perm)) { ++ err = au_wh_init_rw_nolink(h_root, wbr, do_plink, base, &path); ++ if (err > 0) ++ goto out; ++ else if (err) ++ goto out_err; ++ } else { ++ err = au_wh_init_rw(h_root, wbr, do_plink, base, &path); ++ if (err > 0) ++ goto out; ++ else if (err) ++ goto out_err; ++ } ++ goto out; /* success */ ++ ++out_err: ++ pr_err("an error(%d) on the writable branch %pd(%s)\n", ++ err, h_root, au_sbtype(h_root->d_sb)); ++out: ++ for (i = 0; i < AuBrWh_Last; i++) ++ dput(base[i].dentry); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * whiteouts are all hard-linked usually. ++ * when its link count reaches a ceiling, we create a new whiteout base ++ * asynchronously. ++ */ ++ ++struct reinit_br_wh { ++ struct super_block *sb; ++ struct au_branch *br; ++}; ++ ++static void reinit_br_wh(void *arg) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct path h_path; ++ struct reinit_br_wh *a = arg; ++ struct au_wbr *wbr; ++ struct inode *dir, *delegated; ++ struct dentry *h_root; ++ struct au_hinode *hdir; ++ ++ err = 0; ++ wbr = a->br->br_wbr; ++ /* big aufs lock */ ++ si_noflush_write_lock(a->sb); ++ if (!au_br_writable(a->br->br_perm)) ++ goto out; ++ bindex = au_br_index(a->sb, a->br->br_id); ++ if (unlikely(bindex < 0)) ++ goto out; ++ ++ di_read_lock_parent(a->sb->s_root, AuLock_IR); ++ dir = d_inode(a->sb->s_root); ++ hdir = au_hi(dir, bindex); ++ h_root = au_h_dptr(a->sb->s_root, bindex); ++ AuDebugOn(h_root != au_br_dentry(a->br)); ++ ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ wbr_wh_write_lock(wbr); ++ err = au_h_verify(wbr->wbr_whbase, au_opt_udba(a->sb), hdir->hi_inode, ++ h_root, a->br); ++ if (!err) { ++ h_path.dentry = wbr->wbr_whbase; ++ h_path.mnt = au_br_mnt(a->br); ++ delegated = NULL; ++ err = vfsub_unlink(hdir->hi_inode, &h_path, &delegated, ++ /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ } else { ++ pr_warn("%pd is moved, ignored\n", wbr->wbr_whbase); ++ err = 0; ++ } ++ dput(wbr->wbr_whbase); ++ wbr->wbr_whbase = NULL; ++ if (!err) ++ err = au_wh_init(a->br, a->sb); ++ wbr_wh_write_unlock(wbr); ++ au_hn_inode_unlock(hdir); ++ di_read_unlock(a->sb->s_root, AuLock_IR); ++ if (!err) ++ au_fhsm_wrote(a->sb, bindex, /*force*/0); ++ ++out: ++ if (wbr) ++ atomic_dec(&wbr->wbr_wh_running); ++ au_lcnt_dec(&a->br->br_count); ++ si_write_unlock(a->sb); ++ au_nwt_done(&au_sbi(a->sb)->si_nowait); ++ au_kfree_rcu(a); ++ if (unlikely(err)) ++ AuIOErr("err %d\n", err); ++} ++ ++static void kick_reinit_br_wh(struct super_block *sb, struct au_branch *br) ++{ ++ int do_dec, wkq_err; ++ struct reinit_br_wh *arg; ++ ++ do_dec = 1; ++ if (atomic_inc_return(&br->br_wbr->wbr_wh_running) != 1) ++ goto out; ++ ++ /* ignore ENOMEM */ ++ arg = kmalloc(sizeof(*arg), GFP_NOFS); ++ if (arg) { ++ /* ++ * dec(wh_running), kfree(arg) and dec(br_count) ++ * in reinit function ++ */ ++ arg->sb = sb; ++ arg->br = br; ++ au_lcnt_inc(&br->br_count); ++ wkq_err = au_wkq_nowait(reinit_br_wh, arg, sb, /*flags*/0); ++ if (unlikely(wkq_err)) { ++ atomic_dec(&br->br_wbr->wbr_wh_running); ++ au_lcnt_dec(&br->br_count); ++ au_kfree_rcu(arg); ++ } ++ do_dec = 0; ++ } ++ ++out: ++ if (do_dec) ++ atomic_dec(&br->br_wbr->wbr_wh_running); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * create the whiteout @wh. ++ */ ++static int link_or_create_wh(struct super_block *sb, aufs_bindex_t bindex, ++ struct dentry *wh) ++{ ++ int err; ++ struct path h_path = { ++ .dentry = wh ++ }; ++ struct au_branch *br; ++ struct au_wbr *wbr; ++ struct dentry *h_parent; ++ struct inode *h_dir, *delegated; ++ ++ h_parent = wh->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ ++ br = au_sbr(sb, bindex); ++ h_path.mnt = au_br_mnt(br); ++ wbr = br->br_wbr; ++ wbr_wh_read_lock(wbr); ++ if (wbr->wbr_whbase) { ++ delegated = NULL; ++ err = vfsub_link(wbr->wbr_whbase, h_dir, &h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ if (!err || err != -EMLINK) ++ goto out; ++ ++ /* link count full. re-initialize br_whbase. */ ++ kick_reinit_br_wh(sb, br); ++ } ++ ++ /* return this error in this context */ ++ err = vfsub_create(h_dir, &h_path, WH_MASK, /*want_excl*/true); ++ if (!err) ++ au_fhsm_wrote(sb, bindex, /*force*/0); ++ ++out: ++ wbr_wh_read_unlock(wbr); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * create or remove the diropq. ++ */ ++static struct dentry *do_diropq(struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int flags) ++{ ++ struct dentry *opq_dentry; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct path h_path; ++ int err; ++ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, bindex); ++ h_path.dentry = au_h_dptr(dentry, bindex); ++ h_path.mnt = au_br_mnt(br); ++ opq_dentry = vfsub_lkup_one(&diropq_name, &h_path); ++ if (IS_ERR(opq_dentry)) ++ goto out; ++ ++ if (au_ftest_diropq(flags, CREATE)) { ++ err = link_or_create_wh(sb, bindex, opq_dentry); ++ if (!err) { ++ au_set_dbdiropq(dentry, bindex); ++ goto out; /* success */ ++ } ++ } else { ++ h_path.dentry = opq_dentry; ++ err = do_unlink_wh(au_h_iptr(d_inode(dentry), bindex), &h_path); ++ if (!err) ++ au_set_dbdiropq(dentry, -1); ++ } ++ dput(opq_dentry); ++ opq_dentry = ERR_PTR(err); ++ ++out: ++ return opq_dentry; ++} ++ ++struct do_diropq_args { ++ struct dentry **errp; ++ struct dentry *dentry; ++ aufs_bindex_t bindex; ++ unsigned int flags; ++}; ++ ++static void call_do_diropq(void *args) ++{ ++ struct do_diropq_args *a = args; ++ *a->errp = do_diropq(a->dentry, a->bindex, a->flags); ++} ++ ++struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int flags) ++{ ++ struct dentry *diropq, *h_dentry; ++ struct user_namespace *h_userns; ++ ++ h_userns = au_sbr_userns(dentry->d_sb, bindex); ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!au_test_h_perm_sio(h_userns, d_inode(h_dentry), ++ MAY_EXEC | MAY_WRITE)) ++ diropq = do_diropq(dentry, bindex, flags); ++ else { ++ int wkq_err; ++ struct do_diropq_args args = { ++ .errp = &diropq, ++ .dentry = dentry, ++ .bindex = bindex, ++ .flags = flags ++ }; ++ ++ wkq_err = au_wkq_wait(call_do_diropq, &args); ++ if (unlikely(wkq_err)) ++ diropq = ERR_PTR(wkq_err); ++ } ++ ++ return diropq; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * lookup whiteout dentry. ++ * @h_parent: lower parent dentry which must exist and be locked ++ * @base_name: name of dentry which will be whiteouted ++ * returns dentry for whiteout. ++ */ ++struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name, ++ struct au_branch *br) ++{ ++ int err; ++ struct qstr wh_name; ++ struct dentry *wh_dentry; ++ struct path h_path; ++ ++ err = au_wh_name_alloc(&wh_name, base_name); ++ wh_dentry = ERR_PTR(err); ++ if (!err) { ++ h_path.dentry = h_parent; ++ h_path.mnt = au_br_mnt(br); ++ wh_dentry = vfsub_lkup_one(&wh_name, &h_path); ++ au_kfree_try_rcu(wh_name.name); ++ } ++ return wh_dentry; ++} ++ ++/* ++ * link/create a whiteout for @dentry on @bindex. ++ */ ++struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent) ++{ ++ struct dentry *wh_dentry; ++ struct super_block *sb; ++ int err; ++ ++ sb = dentry->d_sb; ++ wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, au_sbr(sb, bindex)); ++ if (!IS_ERR(wh_dentry) && d_is_negative(wh_dentry)) { ++ err = link_or_create_wh(sb, bindex, wh_dentry); ++ if (!err) { ++ au_set_dbwh(dentry, bindex); ++ au_fhsm_wrote(sb, bindex, /*force*/0); ++ } else { ++ dput(wh_dentry); ++ wh_dentry = ERR_PTR(err); ++ } ++ } ++ ++ return wh_dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* Delete all whiteouts in this directory on branch bindex. */ ++static int del_wh_children(struct path *h_path, struct au_nhash *whlist, ++ aufs_bindex_t bindex) ++{ ++ int err; ++ unsigned long ul, n; ++ struct qstr wh_name; ++ char *p; ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ struct au_vdir_destr *str; ++ ++ err = -ENOMEM; ++ p = (void *)__get_free_page(GFP_NOFS); ++ wh_name.name = p; ++ if (unlikely(!wh_name.name)) ++ goto out; ++ ++ err = 0; ++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); ++ p += AUFS_WH_PFX_LEN; ++ n = whlist->nh_num; ++ head = whlist->nh_head; ++ for (ul = 0; !err && ul < n; ul++, head++) { ++ hlist_for_each_entry(pos, head, wh_hash) { ++ if (pos->wh_bindex != bindex) ++ continue; ++ ++ str = &pos->wh_str; ++ if (str->len + AUFS_WH_PFX_LEN <= PATH_MAX) { ++ memcpy(p, str->name, str->len); ++ wh_name.len = AUFS_WH_PFX_LEN + str->len; ++ err = unlink_wh_name(h_path, &wh_name); ++ if (!err) ++ continue; ++ break; ++ } ++ AuIOErr("whiteout name too long %.*s\n", ++ str->len, str->name); ++ err = -EIO; ++ break; ++ } ++ } ++ free_page((unsigned long)wh_name.name); ++ ++out: ++ return err; ++} ++ ++struct del_wh_children_args { ++ int *errp; ++ struct path *h_path; ++ struct au_nhash *whlist; ++ aufs_bindex_t bindex; ++}; ++ ++static void call_del_wh_children(void *args) ++{ ++ struct del_wh_children_args *a = args; ++ *a->errp = del_wh_children(a->h_path, a->whlist, a->bindex); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp) ++{ ++ struct au_whtmp_rmdir *whtmp; ++ int err; ++ unsigned int rdhash; ++ ++ SiMustAnyLock(sb); ++ ++ whtmp = kzalloc(sizeof(*whtmp), gfp); ++ if (unlikely(!whtmp)) { ++ whtmp = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ ++ /* no estimation for dir size */ ++ rdhash = au_sbi(sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = AUFS_RDHASH_DEF; ++ err = au_nhash_alloc(&whtmp->whlist, rdhash, gfp); ++ if (unlikely(err)) { ++ au_kfree_rcu(whtmp); ++ whtmp = ERR_PTR(err); ++ } ++ ++out: ++ return whtmp; ++} ++ ++void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp) ++{ ++ if (whtmp->br) ++ au_lcnt_dec(&whtmp->br->br_count); ++ dput(whtmp->wh_dentry); ++ iput(whtmp->dir); ++ au_nhash_wh_free(&whtmp->whlist); ++ au_kfree_rcu(whtmp); ++} ++ ++/* ++ * rmdir the whiteouted temporary named dir @h_dentry. ++ * @whlist: whiteouted children. ++ */ ++int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct au_nhash *whlist) ++{ ++ int err; ++ unsigned int h_nlink; ++ struct path wh_path; ++ struct inode *wh_inode, *h_dir; ++ struct au_branch *br; ++ struct user_namespace *h_userns; ++ ++ h_dir = d_inode(wh_dentry->d_parent); /* dir inode is locked */ ++ IMustLock(h_dir); ++ ++ br = au_sbr(dir->i_sb, bindex); ++ wh_path.dentry = wh_dentry; ++ wh_path.mnt = au_br_mnt(br); ++ h_userns = au_br_userns(br); ++ wh_inode = d_inode(wh_dentry); ++ inode_lock_nested(wh_inode, AuLsc_I_CHILD); ++ ++ /* ++ * someone else might change some whiteouts while we were sleeping. ++ * it means this whlist may have an obsoleted entry. ++ */ ++ if (!au_test_h_perm_sio(h_userns, wh_inode, MAY_EXEC | MAY_WRITE)) ++ err = del_wh_children(&wh_path, whlist, bindex); ++ else { ++ int wkq_err; ++ struct del_wh_children_args args = { ++ .errp = &err, ++ .h_path = &wh_path, ++ .whlist = whlist, ++ .bindex = bindex ++ }; ++ ++ wkq_err = au_wkq_wait(call_del_wh_children, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ inode_unlock(wh_inode); ++ ++ if (!err) { ++ h_nlink = h_dir->i_nlink; ++ err = vfsub_rmdir(h_dir, &wh_path); ++ /* some fs doesn't change the parent nlink in some cases */ ++ h_nlink -= h_dir->i_nlink; ++ } ++ ++ if (!err) { ++ if (au_ibtop(dir) == bindex) { ++ /* todo: dir->i_mutex is necessary */ ++ au_cpup_attr_timesizes(dir); ++ if (h_nlink) ++ vfsub_drop_nlink(dir); ++ } ++ return 0; /* success */ ++ } ++ ++ pr_warn("failed removing %pd(%d), ignored\n", wh_dentry, err); ++ return err; ++} ++ ++static void call_rmdir_whtmp(void *args) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct au_whtmp_rmdir *a = args; ++ struct super_block *sb; ++ struct dentry *h_parent; ++ struct inode *h_dir; ++ struct au_hinode *hdir; ++ ++ /* rmdir by nfsd may cause deadlock with this i_mutex */ ++ /* inode_lock(a->dir); */ ++ err = -EROFS; ++ sb = a->dir->i_sb; ++ si_read_lock(sb, !AuLock_FLUSH); ++ if (!au_br_writable(a->br->br_perm)) ++ goto out; ++ bindex = au_br_index(sb, a->br->br_id); ++ if (unlikely(bindex < 0)) ++ goto out; ++ ++ err = -EIO; ++ ii_write_lock_parent(a->dir); ++ h_parent = dget_parent(a->wh_dentry); ++ h_dir = d_inode(h_parent); ++ hdir = au_hi(a->dir, bindex); ++ err = vfsub_mnt_want_write(au_br_mnt(a->br)); ++ if (unlikely(err)) ++ goto out_mnt; ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ err = au_h_verify(a->wh_dentry, au_opt_udba(sb), h_dir, h_parent, ++ a->br); ++ if (!err) ++ err = au_whtmp_rmdir(a->dir, bindex, a->wh_dentry, &a->whlist); ++ au_hn_inode_unlock(hdir); ++ vfsub_mnt_drop_write(au_br_mnt(a->br)); ++ ++out_mnt: ++ dput(h_parent); ++ ii_write_unlock(a->dir); ++out: ++ /* inode_unlock(a->dir); */ ++ au_whtmp_rmdir_free(a); ++ si_read_unlock(sb); ++ au_nwt_done(&au_sbi(sb)->si_nowait); ++ if (unlikely(err)) ++ AuIOErr("err %d\n", err); ++} ++ ++void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct au_whtmp_rmdir *args) ++{ ++ int wkq_err; ++ struct super_block *sb; ++ ++ IMustLock(dir); ++ ++ /* all post-process will be done in do_rmdir_whtmp(). */ ++ sb = dir->i_sb; ++ args->dir = au_igrab(dir); ++ args->br = au_sbr(sb, bindex); ++ au_lcnt_inc(&args->br->br_count); ++ args->wh_dentry = dget(wh_dentry); ++ wkq_err = au_wkq_nowait(call_rmdir_whtmp, args, sb, /*flags*/0); ++ if (unlikely(wkq_err)) { ++ pr_warn("rmdir error %pd (%d), ignored\n", wh_dentry, wkq_err); ++ au_whtmp_rmdir_free(args); ++ } ++} +diff -Nurp linux-5.15.37/fs/aufs/whout.h linux-5.15.37-aufs/fs/aufs/whout.h +--- linux-5.15.37/fs/aufs/whout.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/whout.h 2022-04-08 20:22:30.616616670 +0300 +@@ -0,0 +1,74 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * whiteout for logical deletion and opaque directory ++ */ ++ ++#ifndef __AUFS_WHOUT_H__ ++#define __AUFS_WHOUT_H__ ++ ++#ifdef __KERNEL__ ++ ++#include "dir.h" ++ ++/* whout.c */ ++int au_wh_name_alloc(struct qstr *wh, const struct qstr *name); ++int au_wh_test(struct user_namespace *h_userns, struct path *h_ppath, ++ struct qstr *wh_name, int try_sio); ++int au_diropq_test(struct user_namespace *h_userns, struct path *h_path); ++struct au_branch; ++struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br, ++ struct qstr *prefix); ++int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br); ++int au_wh_unlink_dentry(struct inode *h_dir, struct path *h_path, ++ struct dentry *dentry); ++int au_wh_init(struct au_branch *br, struct super_block *sb); ++ ++/* diropq flags */ ++#define AuDiropq_CREATE 1 ++#define au_ftest_diropq(flags, name) ((flags) & AuDiropq_##name) ++#define au_fset_diropq(flags, name) \ ++ do { (flags) |= AuDiropq_##name; } while (0) ++#define au_fclr_diropq(flags, name) \ ++ do { (flags) &= ~AuDiropq_##name; } while (0) ++ ++struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int flags); ++struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name, ++ struct au_branch *br); ++struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent); ++ ++/* real rmdir for the whiteout-ed dir */ ++struct au_whtmp_rmdir { ++ struct inode *dir; ++ struct au_branch *br; ++ struct dentry *wh_dentry; ++ struct au_nhash whlist; ++}; ++ ++struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp); ++void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp); ++int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct au_nhash *whlist); ++void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct au_whtmp_rmdir *args); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct dentry *au_diropq_create(struct dentry *dentry, ++ aufs_bindex_t bindex) ++{ ++ return au_diropq_sio(dentry, bindex, AuDiropq_CREATE); ++} ++ ++static inline int au_diropq_remove(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ return PTR_ERR(au_diropq_sio(dentry, bindex, !AuDiropq_CREATE)); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_WHOUT_H__ */ +diff -Nurp linux-5.15.37/fs/aufs/wkq.c linux-5.15.37-aufs/fs/aufs/wkq.c +--- linux-5.15.37/fs/aufs/wkq.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/wkq.c 2022-04-08 20:22:30.616616670 +0300 +@@ -0,0 +1,359 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * workqueue for asynchronous/super-io operations ++ * todo: try new credential scheme ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* internal workqueue named AUFS_WKQ_NAME */ ++ ++static struct workqueue_struct *au_wkq; ++ ++struct au_wkinfo { ++ struct work_struct wk; ++ struct kobject *kobj; ++ ++ unsigned int flags; /* see wkq.h */ ++ ++ au_wkq_func_t func; ++ void *args; ++ ++#ifdef CONFIG_LOCKDEP ++ int dont_check; ++ struct held_lock **hlock; ++#endif ++ ++ struct completion *comp; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * Aufs passes some operations to the workqueue such as the internal copyup. ++ * This scheme looks rather unnatural for LOCKDEP debugging feature, since the ++ * job run by workqueue depends upon the locks acquired in the other task. ++ * Delegating a small operation to the workqueue, aufs passes its lockdep ++ * information too. And the job in the workqueue restores the info in order to ++ * pretend as if it acquired those locks. This is just to make LOCKDEP work ++ * correctly and expectedly. ++ */ ++ ++#ifndef CONFIG_LOCKDEP ++AuStubInt0(au_wkq_lockdep_alloc, struct au_wkinfo *wkinfo); ++AuStubVoid(au_wkq_lockdep_free, struct au_wkinfo *wkinfo); ++AuStubVoid(au_wkq_lockdep_pre, struct au_wkinfo *wkinfo); ++AuStubVoid(au_wkq_lockdep_post, struct au_wkinfo *wkinfo); ++AuStubVoid(au_wkq_lockdep_init, struct au_wkinfo *wkinfo); ++#else ++static void au_wkq_lockdep_init(struct au_wkinfo *wkinfo) ++{ ++ wkinfo->hlock = NULL; ++ wkinfo->dont_check = 0; ++} ++ ++/* ++ * 1: matched ++ * 0: unmatched ++ */ ++static int au_wkq_lockdep_test(struct lock_class_key *key, const char *name) ++{ ++ static DEFINE_SPINLOCK(spin); ++ static struct { ++ char *name; ++ struct lock_class_key *key; ++ } a[] = { ++ { .name = "&sbinfo->si_rwsem" }, ++ { .name = "&finfo->fi_rwsem" }, ++ { .name = "&dinfo->di_rwsem" }, ++ { .name = "&iinfo->ii_rwsem" } ++ }; ++ static int set; ++ int i; ++ ++ /* lockless read from 'set.' see below */ ++ if (set == ARRAY_SIZE(a)) { ++ for (i = 0; i < ARRAY_SIZE(a); i++) ++ if (a[i].key == key) ++ goto match; ++ goto unmatch; ++ } ++ ++ spin_lock(&spin); ++ if (set) ++ for (i = 0; i < ARRAY_SIZE(a); i++) ++ if (a[i].key == key) { ++ spin_unlock(&spin); ++ goto match; ++ } ++ for (i = 0; i < ARRAY_SIZE(a); i++) { ++ if (a[i].key) { ++ if (unlikely(a[i].key == key)) { /* rare but possible */ ++ spin_unlock(&spin); ++ goto match; ++ } else ++ continue; ++ } ++ if (strstr(a[i].name, name)) { ++ /* ++ * the order of these three lines is important for the ++ * lockless read above. ++ */ ++ a[i].key = key; ++ spin_unlock(&spin); ++ set++; ++ /* AuDbg("%d, %s\n", set, name); */ ++ goto match; ++ } ++ } ++ spin_unlock(&spin); ++ goto unmatch; ++ ++match: ++ return 1; ++unmatch: ++ return 0; ++} ++ ++static int au_wkq_lockdep_alloc(struct au_wkinfo *wkinfo) ++{ ++ int err, n; ++ struct task_struct *curr; ++ struct held_lock **hl, *held_locks, *p; ++ ++ err = 0; ++ curr = current; ++ wkinfo->dont_check = lockdep_recursing(curr); ++ if (wkinfo->dont_check) ++ goto out; ++ n = curr->lockdep_depth; ++ if (!n) ++ goto out; ++ ++ err = -ENOMEM; ++ wkinfo->hlock = kmalloc_array(n + 1, sizeof(*wkinfo->hlock), GFP_NOFS); ++ if (unlikely(!wkinfo->hlock)) ++ goto out; ++ ++ err = 0; ++#if 0 /* left for debugging */ ++ if (0 && au_debug_test()) ++ lockdep_print_held_locks(curr); ++#endif ++ held_locks = curr->held_locks; ++ hl = wkinfo->hlock; ++ while (n--) { ++ p = held_locks++; ++ if (au_wkq_lockdep_test(p->instance->key, p->instance->name)) ++ *hl++ = p; ++ } ++ *hl = NULL; ++ ++out: ++ return err; ++} ++ ++static void au_wkq_lockdep_free(struct au_wkinfo *wkinfo) ++{ ++ au_kfree_try_rcu(wkinfo->hlock); ++} ++ ++static void au_wkq_lockdep_pre(struct au_wkinfo *wkinfo) ++{ ++ struct held_lock *p, **hl = wkinfo->hlock; ++ int subclass; ++ ++ if (wkinfo->dont_check) ++ lockdep_off(); ++ if (!hl) ++ return; ++ while ((p = *hl++)) { /* assignment */ ++ subclass = lockdep_hlock_class(p)->subclass; ++ /* AuDbg("%s, %d\n", p->instance->name, subclass); */ ++ if (p->read) ++ rwsem_acquire_read(p->instance, subclass, 0, ++ /*p->acquire_ip*/_RET_IP_); ++ else ++ rwsem_acquire(p->instance, subclass, 0, ++ /*p->acquire_ip*/_RET_IP_); ++ } ++} ++ ++static void au_wkq_lockdep_post(struct au_wkinfo *wkinfo) ++{ ++ struct held_lock *p, **hl = wkinfo->hlock; ++ ++ if (wkinfo->dont_check) ++ lockdep_on(); ++ if (!hl) ++ return; ++ while ((p = *hl++)) /* assignment */ ++ rwsem_release(p->instance, /*p->acquire_ip*/_RET_IP_); ++} ++#endif ++ ++static void wkq_func(struct work_struct *wk) ++{ ++ struct au_wkinfo *wkinfo = container_of(wk, struct au_wkinfo, wk); ++ ++ AuDebugOn(!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)); ++ AuDebugOn(rlimit(RLIMIT_FSIZE) != RLIM_INFINITY); ++ ++ au_wkq_lockdep_pre(wkinfo); ++ wkinfo->func(wkinfo->args); ++ au_wkq_lockdep_post(wkinfo); ++ if (au_ftest_wkq(wkinfo->flags, WAIT)) ++ complete(wkinfo->comp); ++ else { ++ kobject_put(wkinfo->kobj); ++ module_put(THIS_MODULE); /* todo: ?? */ ++ au_kfree_rcu(wkinfo); ++ } ++} ++ ++/* ++ * Since struct completion is large, try allocating it dynamically. ++ */ ++#define AuWkqCompDeclare(name) struct completion *comp = NULL ++ ++static int au_wkq_comp_alloc(struct au_wkinfo *wkinfo, struct completion **comp) ++{ ++ *comp = kmalloc(sizeof(**comp), GFP_NOFS); ++ if (*comp) { ++ init_completion(*comp); ++ wkinfo->comp = *comp; ++ return 0; ++ } ++ return -ENOMEM; ++} ++ ++static void au_wkq_comp_free(struct completion *comp) ++{ ++ au_kfree_rcu(comp); ++} ++ ++static void au_wkq_run(struct au_wkinfo *wkinfo) ++{ ++ if (au_ftest_wkq(wkinfo->flags, NEST)) { ++ if (au_wkq_test()) { ++ AuWarn1("wkq from wkq, unless silly-rename on NFS," ++ " due to a dead dir by UDBA," ++ " or async xino write?\n"); ++ AuDebugOn(au_ftest_wkq(wkinfo->flags, WAIT)); ++ } ++ } else ++ au_dbg_verify_kthread(); ++ ++ if (au_ftest_wkq(wkinfo->flags, WAIT)) { ++ INIT_WORK_ONSTACK(&wkinfo->wk, wkq_func); ++ queue_work(au_wkq, &wkinfo->wk); ++ } else { ++ INIT_WORK(&wkinfo->wk, wkq_func); ++ schedule_work(&wkinfo->wk); ++ } ++} ++ ++/* ++ * Be careful. It is easy to make deadlock happen. ++ * processA: lock, wkq and wait ++ * processB: wkq and wait, lock in wkq ++ * --> deadlock ++ */ ++int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args) ++{ ++ int err; ++ AuWkqCompDeclare(comp); ++ struct au_wkinfo wkinfo = { ++ .flags = flags, ++ .func = func, ++ .args = args ++ }; ++ ++ err = au_wkq_comp_alloc(&wkinfo, &comp); ++ if (unlikely(err)) ++ goto out; ++ err = au_wkq_lockdep_alloc(&wkinfo); ++ if (unlikely(err)) ++ goto out_comp; ++ if (!err) { ++ au_wkq_run(&wkinfo); ++ /* no timeout, no interrupt */ ++ wait_for_completion(wkinfo.comp); ++ } ++ au_wkq_lockdep_free(&wkinfo); ++ ++out_comp: ++ au_wkq_comp_free(comp); ++out: ++ destroy_work_on_stack(&wkinfo.wk); ++ return err; ++} ++ ++/* ++ * Note: dget/dput() in func for aufs dentries are not supported. It will be a ++ * problem in a concurrent umounting. ++ */ ++int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb, ++ unsigned int flags) ++{ ++ int err; ++ struct au_wkinfo *wkinfo; ++ ++ atomic_inc(&au_sbi(sb)->si_nowait.nw_len); ++ ++ /* ++ * wkq_func() must free this wkinfo. ++ * it highly depends upon the implementation of workqueue. ++ */ ++ err = 0; ++ wkinfo = kmalloc(sizeof(*wkinfo), GFP_NOFS); ++ if (wkinfo) { ++ wkinfo->kobj = &au_sbi(sb)->si_kobj; ++ wkinfo->flags = flags & ~AuWkq_WAIT; ++ wkinfo->func = func; ++ wkinfo->args = args; ++ wkinfo->comp = NULL; ++ au_wkq_lockdep_init(wkinfo); ++ kobject_get(wkinfo->kobj); ++ __module_get(THIS_MODULE); /* todo: ?? */ ++ ++ au_wkq_run(wkinfo); ++ } else { ++ err = -ENOMEM; ++ au_nwt_done(&au_sbi(sb)->si_nowait); ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_nwt_init(struct au_nowait_tasks *nwt) ++{ ++ atomic_set(&nwt->nw_len, 0); ++ /* smp_mb(); */ /* atomic_set */ ++ init_waitqueue_head(&nwt->nw_wq); ++} ++ ++void au_wkq_fin(void) ++{ ++ destroy_workqueue(au_wkq); ++} ++ ++int __init au_wkq_init(void) ++{ ++ int err; ++ ++ err = 0; ++ au_wkq = alloc_workqueue(AUFS_WKQ_NAME, 0, WQ_DFL_ACTIVE); ++ if (IS_ERR(au_wkq)) ++ err = PTR_ERR(au_wkq); ++ else if (!au_wkq) ++ err = -ENOMEM; ++ ++ return err; ++} +diff -Nurp linux-5.15.37/fs/aufs/wkq.h linux-5.15.37-aufs/fs/aufs/wkq.h +--- linux-5.15.37/fs/aufs/wkq.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/wkq.h 2022-04-08 20:22:30.616616670 +0300 +@@ -0,0 +1,76 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * workqueue for asynchronous/super-io operations ++ * todo: try new credentials management scheme ++ */ ++ ++#ifndef __AUFS_WKQ_H__ ++#define __AUFS_WKQ_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++struct super_block; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * in the next operation, wait for the 'nowait' tasks in system-wide workqueue ++ */ ++struct au_nowait_tasks { ++ atomic_t nw_len; ++ wait_queue_head_t nw_wq; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++typedef void (*au_wkq_func_t)(void *args); ++ ++/* wkq flags */ ++#define AuWkq_WAIT 1 ++#define AuWkq_NEST (1 << 1) ++#define au_ftest_wkq(flags, name) ((flags) & AuWkq_##name) ++#define au_fset_wkq(flags, name) \ ++ do { (flags) |= AuWkq_##name; } while (0) ++#define au_fclr_wkq(flags, name) \ ++ do { (flags) &= ~AuWkq_##name; } while (0) ++ ++/* wkq.c */ ++int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args); ++int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb, ++ unsigned int flags); ++void au_nwt_init(struct au_nowait_tasks *nwt); ++int __init au_wkq_init(void); ++void au_wkq_fin(void); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline int au_wkq_test(void) ++{ ++ return current->flags & PF_WQ_WORKER; ++} ++ ++static inline int au_wkq_wait(au_wkq_func_t func, void *args) ++{ ++ return au_wkq_do_wait(AuWkq_WAIT, func, args); ++} ++ ++static inline void au_nwt_done(struct au_nowait_tasks *nwt) ++{ ++ if (atomic_dec_and_test(&nwt->nw_len)) ++ wake_up_all(&nwt->nw_wq); ++} ++ ++static inline int au_nwt_flush(struct au_nowait_tasks *nwt) ++{ ++ wait_event(nwt->nw_wq, !atomic_read(&nwt->nw_len)); ++ return 0; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_WKQ_H__ */ +diff -Nurp linux-5.15.37/fs/aufs/xattr.c linux-5.15.37-aufs/fs/aufs/xattr.c +--- linux-5.15.37/fs/aufs/xattr.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/xattr.c 2022-04-08 20:22:30.616616670 +0300 +@@ -0,0 +1,355 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2014-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * handling xattr functions ++ */ ++ ++#include ++#include ++#include ++#include "aufs.h" ++ ++static int au_xattr_ignore(int err, char *name, unsigned int ignore_flags) ++{ ++ if (!ignore_flags) ++ goto out; ++ switch (err) { ++ case -ENOMEM: ++ case -EDQUOT: ++ goto out; ++ } ++ ++ if ((ignore_flags & AuBrAttr_ICEX) == AuBrAttr_ICEX) { ++ err = 0; ++ goto out; ++ } ++ ++#define cmp(brattr, prefix) do { \ ++ if (!strncmp(name, XATTR_##prefix##_PREFIX, \ ++ XATTR_##prefix##_PREFIX_LEN)) { \ ++ if (ignore_flags & AuBrAttr_ICEX_##brattr) \ ++ err = 0; \ ++ goto out; \ ++ } \ ++ } while (0) ++ ++ cmp(SEC, SECURITY); ++ cmp(SYS, SYSTEM); ++ cmp(TR, TRUSTED); ++ cmp(USR, USER); ++#undef cmp ++ ++ if (ignore_flags & AuBrAttr_ICEX_OTH) ++ err = 0; ++ ++out: ++ return err; ++} ++ ++static const int au_xattr_out_of_list = AuBrAttr_ICEX_OTH << 1; ++ ++static int au_do_cpup_xattr(struct path *h_dst, struct path *h_src, ++ char *name, char **buf, unsigned int ignore_flags, ++ unsigned int verbose) ++{ ++ int err; ++ ssize_t ssz; ++ struct inode *h_idst; ++ struct dentry *h_dst_dentry, *h_src_dentry; ++ struct user_namespace *h_dst_userns, *h_src_userns; ++ ++ h_src_userns = mnt_user_ns(h_src->mnt); ++ h_src_dentry = h_src->dentry; ++ ssz = vfs_getxattr_alloc(h_src_userns, h_src_dentry, name, buf, 0, ++ GFP_NOFS); ++ err = ssz; ++ if (unlikely(err <= 0)) { ++ if (err == -ENODATA ++ || (err == -EOPNOTSUPP ++ && ((ignore_flags & au_xattr_out_of_list) ++ || (au_test_nfs_noacl(d_inode(h_src_dentry)) ++ && (!strcmp(name, XATTR_NAME_POSIX_ACL_ACCESS) ++ || !strcmp(name, ++ XATTR_NAME_POSIX_ACL_DEFAULT)))) ++ )) ++ err = 0; ++ if (err && (verbose || au_debug_test())) ++ pr_err("%s, err %d\n", name, err); ++ goto out; ++ } ++ ++ /* unlock it temporary */ ++ h_dst_userns = mnt_user_ns(h_dst->mnt); ++ h_dst_dentry = h_dst->dentry; ++ h_idst = d_inode(h_dst_dentry); ++ inode_unlock(h_idst); ++ err = vfsub_setxattr(h_dst_userns, h_dst_dentry, name, *buf, ssz, ++ /*flags*/0); ++ inode_lock_nested(h_idst, AuLsc_I_CHILD2); ++ if (unlikely(err)) { ++ if (verbose || au_debug_test()) ++ pr_err("%s, err %d\n", name, err); ++ err = au_xattr_ignore(err, name, ignore_flags); ++ } ++ ++out: ++ return err; ++} ++ ++int au_cpup_xattr(struct path *h_dst, struct path *h_src, int ignore_flags, ++ unsigned int verbose) ++{ ++ int err, unlocked, acl_access, acl_default; ++ ssize_t ssz; ++ struct dentry *h_dst_dentry, *h_src_dentry; ++ struct inode *h_isrc, *h_idst; ++ char *value, *p, *o, *e; ++ ++ /* try stopping to update the source inode while we are referencing */ ++ /* there should not be the parent-child relationship between them */ ++ h_dst_dentry = h_dst->dentry; ++ h_idst = d_inode(h_dst_dentry); ++ h_src_dentry = h_src->dentry; ++ h_isrc = d_inode(h_src_dentry); ++ inode_unlock(h_idst); ++ inode_lock_shared_nested(h_isrc, AuLsc_I_CHILD); ++ inode_lock_nested(h_idst, AuLsc_I_CHILD2); ++ unlocked = 0; ++ ++ /* some filesystems don't list POSIX ACL, for example tmpfs */ ++ ssz = vfs_listxattr(h_src_dentry, NULL, 0); ++ err = ssz; ++ if (unlikely(err < 0)) { ++ AuTraceErr(err); ++ if (err == -ENODATA ++ || err == -EOPNOTSUPP) ++ err = 0; /* ignore */ ++ goto out; ++ } ++ ++ err = 0; ++ p = NULL; ++ o = NULL; ++ if (ssz) { ++ err = -ENOMEM; ++ p = kmalloc(ssz, GFP_NOFS); ++ o = p; ++ if (unlikely(!p)) ++ goto out; ++ err = vfs_listxattr(h_src_dentry, p, ssz); ++ } ++ inode_unlock_shared(h_isrc); ++ unlocked = 1; ++ AuDbg("err %d, ssz %zd\n", err, ssz); ++ if (unlikely(err < 0)) ++ goto out_free; ++ ++ err = 0; ++ e = p + ssz; ++ value = NULL; ++ acl_access = 0; ++ acl_default = 0; ++ while (!err && p < e) { ++ acl_access |= !strncmp(p, XATTR_NAME_POSIX_ACL_ACCESS, ++ sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1); ++ acl_default |= !strncmp(p, XATTR_NAME_POSIX_ACL_DEFAULT, ++ sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) ++ - 1); ++ err = au_do_cpup_xattr(h_dst, h_src, p, &value, ignore_flags, ++ verbose); ++ p += strlen(p) + 1; ++ } ++ AuTraceErr(err); ++ ignore_flags |= au_xattr_out_of_list; ++ if (!err && !acl_access) { ++ err = au_do_cpup_xattr(h_dst, h_src, ++ XATTR_NAME_POSIX_ACL_ACCESS, &value, ++ ignore_flags, verbose); ++ AuTraceErr(err); ++ } ++ if (!err && !acl_default) { ++ err = au_do_cpup_xattr(h_dst, h_src, ++ XATTR_NAME_POSIX_ACL_DEFAULT, &value, ++ ignore_flags, verbose); ++ AuTraceErr(err); ++ } ++ ++ au_kfree_try_rcu(value); ++ ++out_free: ++ au_kfree_try_rcu(o); ++out: ++ if (!unlocked) ++ inode_unlock_shared(h_isrc); ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_smack_reentering(struct super_block *sb) ++{ ++#if IS_ENABLED(CONFIG_SECURITY_SMACK) || IS_ENABLED(CONFIG_SECURITY_SELINUX) ++ /* ++ * as a part of lookup, smack_d_instantiate() is called, and it calls ++ * i_op->getxattr(). ouch. ++ */ ++ return si_pid_test(sb); ++#else ++ return 0; ++#endif ++} ++ ++enum { ++ AU_XATTR_LIST, ++ AU_XATTR_GET ++}; ++ ++struct au_lgxattr { ++ int type; ++ union { ++ struct { ++ char *list; ++ size_t size; ++ } list; ++ struct { ++ const char *name; ++ void *value; ++ size_t size; ++ } get; ++ } u; ++}; ++ ++static ssize_t au_lgxattr(struct dentry *dentry, struct inode *inode, ++ struct au_lgxattr *arg) ++{ ++ ssize_t err; ++ int reenter; ++ struct path h_path; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ reenter = au_smack_reentering(sb); ++ if (!reenter) { ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out; ++ } ++ err = au_h_path_getattr(dentry, inode, /*force*/1, &h_path, reenter); ++ if (unlikely(err)) ++ goto out_si; ++ if (unlikely(!h_path.dentry)) ++ /* illegally overlapped or something */ ++ goto out_di; /* pretending success */ ++ ++ /* always topmost entry only */ ++ switch (arg->type) { ++ case AU_XATTR_LIST: ++ err = vfs_listxattr(h_path.dentry, ++ arg->u.list.list, arg->u.list.size); ++ break; ++ case AU_XATTR_GET: ++ AuDebugOn(d_is_negative(h_path.dentry)); ++ err = vfs_getxattr(mnt_user_ns(h_path.mnt), h_path.dentry, ++ arg->u.get.name, arg->u.get.value, ++ arg->u.get.size); ++ break; ++ } ++ ++out_di: ++ if (!reenter) ++ di_read_unlock(dentry, AuLock_IR); ++out_si: ++ if (!reenter) ++ si_read_unlock(sb); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++ssize_t aufs_listxattr(struct dentry *dentry, char *list, size_t size) ++{ ++ struct au_lgxattr arg = { ++ .type = AU_XATTR_LIST, ++ .u.list = { ++ .list = list, ++ .size = size ++ }, ++ }; ++ ++ return au_lgxattr(dentry, /*inode*/NULL, &arg); ++} ++ ++static ssize_t au_getxattr(struct dentry *dentry, struct inode *inode, ++ const char *name, void *value, size_t size) ++{ ++ struct au_lgxattr arg = { ++ .type = AU_XATTR_GET, ++ .u.get = { ++ .name = name, ++ .value = value, ++ .size = size ++ }, ++ }; ++ ++ return au_lgxattr(dentry, inode, &arg); ++} ++ ++static int au_setxattr(struct dentry *dentry, struct inode *inode, ++ const char *name, const void *value, size_t size, ++ int flags) ++{ ++ struct au_sxattr arg = { ++ .type = AU_XATTR_SET, ++ .u.set = { ++ .name = name, ++ .value = value, ++ .size = size, ++ .flags = flags ++ }, ++ }; ++ ++ return au_sxattr(dentry, inode, &arg); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_xattr_get(const struct xattr_handler *handler, ++ struct dentry *dentry, struct inode *inode, ++ const char *name, void *buffer, size_t size) ++{ ++ return au_getxattr(dentry, inode, name, buffer, size); ++} ++ ++static int au_xattr_set(const struct xattr_handler *handler, ++ struct user_namespace *userns, ++ struct dentry *dentry, struct inode *inode, ++ const char *name, const void *value, size_t size, ++ int flags) ++{ ++ return au_setxattr(dentry, inode, name, value, size, flags); ++} ++ ++static const struct xattr_handler au_xattr_handler = { ++ .name = "", ++ .prefix = "", ++ .get = au_xattr_get, ++ .set = au_xattr_set ++}; ++ ++static const struct xattr_handler *au_xattr_handlers[] = { ++#ifdef CONFIG_FS_POSIX_ACL ++ &posix_acl_access_xattr_handler, ++ &posix_acl_default_xattr_handler, ++#endif ++ &au_xattr_handler, /* must be last */ ++ NULL ++}; ++ ++void au_xattr_init(struct super_block *sb) ++{ ++ sb->s_xattr = au_xattr_handlers; ++} +diff -Nurp linux-5.15.37/fs/aufs/xino.c linux-5.15.37-aufs/fs/aufs/xino.c +--- linux-5.15.37/fs/aufs/xino.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/fs/aufs/xino.c 2022-04-08 20:22:30.616616670 +0300 +@@ -0,0 +1,1913 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++/* ++ * external inode number translation table and bitmap ++ * ++ * things to consider ++ * - the lifetime ++ * + au_xino object ++ * + XINO files (xino, xib, xigen) ++ * + dynamic debugfs entries (xiN) ++ * + static debugfs entries (xib, xigen) ++ * + static sysfs entry (xi_path) ++ * - several entry points to handle them. ++ * + mount(2) without xino option (default) ++ * + mount(2) with xino option ++ * + mount(2) with noxino option ++ * + umount(2) ++ * + remount with add/del branches ++ * + remount with xino/noxino options ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++static aufs_bindex_t sbr_find_shared(struct super_block *sb, aufs_bindex_t btop, ++ aufs_bindex_t bbot, ++ struct super_block *h_sb) ++{ ++ /* todo: try binary-search if the branches are many */ ++ for (; btop <= bbot; btop++) ++ if (h_sb == au_sbr_sb(sb, btop)) ++ return btop; ++ return -1; ++} ++ ++/* ++ * find another branch who is on the same filesystem of the specified ++ * branch{@btgt}. search until @bbot. ++ */ ++static aufs_bindex_t is_sb_shared(struct super_block *sb, aufs_bindex_t btgt, ++ aufs_bindex_t bbot) ++{ ++ aufs_bindex_t bindex; ++ struct super_block *tgt_sb; ++ ++ tgt_sb = au_sbr_sb(sb, btgt); ++ bindex = sbr_find_shared(sb, /*btop*/0, btgt - 1, tgt_sb); ++ if (bindex < 0) ++ bindex = sbr_find_shared(sb, btgt + 1, bbot, tgt_sb); ++ ++ return bindex; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * stop unnecessary notify events at creating xino files ++ */ ++ ++aufs_bindex_t au_xi_root(struct super_block *sb, struct dentry *dentry) ++{ ++ aufs_bindex_t bfound, bindex, bbot; ++ struct dentry *parent; ++ struct au_branch *br; ++ ++ bfound = -1; ++ parent = dentry->d_parent; /* safe d_parent access */ ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_dentry(br) == parent) { ++ bfound = bindex; ++ break; ++ } ++ } ++ ++ AuDbg("bfound b%d\n", bfound); ++ return bfound; ++} ++ ++struct au_xino_lock_dir { ++ struct au_hinode *hdir; ++ struct dentry *parent; ++ struct inode *dir; ++}; ++ ++static struct dentry *au_dget_parent_lock(struct dentry *dentry, ++ unsigned int lsc) ++{ ++ struct dentry *parent; ++ struct inode *dir; ++ ++ parent = dget_parent(dentry); ++ dir = d_inode(parent); ++ inode_lock_nested(dir, lsc); ++#if 0 /* it should not happen */ ++ spin_lock(&dentry->d_lock); ++ if (unlikely(dentry->d_parent != parent)) { ++ spin_unlock(&dentry->d_lock); ++ inode_unlock(dir); ++ dput(parent); ++ parent = NULL; ++ goto out; ++ } ++ spin_unlock(&dentry->d_lock); ++ ++out: ++#endif ++ return parent; ++} ++ ++static void au_xino_lock_dir(struct super_block *sb, struct path *xipath, ++ struct au_xino_lock_dir *ldir) ++{ ++ aufs_bindex_t bindex; ++ ++ ldir->hdir = NULL; ++ bindex = au_xi_root(sb, xipath->dentry); ++ if (bindex >= 0) { ++ /* rw branch root */ ++ ldir->hdir = au_hi(d_inode(sb->s_root), bindex); ++ au_hn_inode_lock_nested(ldir->hdir, AuLsc_I_PARENT); ++ } else { ++ /* other */ ++ ldir->parent = au_dget_parent_lock(xipath->dentry, ++ AuLsc_I_PARENT); ++ ldir->dir = d_inode(ldir->parent); ++ } ++} ++ ++static void au_xino_unlock_dir(struct au_xino_lock_dir *ldir) ++{ ++ if (ldir->hdir) ++ au_hn_inode_unlock(ldir->hdir); ++ else { ++ inode_unlock(ldir->dir); ++ dput(ldir->parent); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * create and set a new xino file ++ */ ++struct file *au_xino_create(struct super_block *sb, char *fpath, int silent, ++ int wbrtop) ++{ ++ struct file *file; ++ struct dentry *h_parent, *d; ++ struct inode *h_dir, *inode; ++ int err; ++ static DEFINE_MUTEX(mtx); ++ ++ /* ++ * at mount-time, and the xino file is the default path, ++ * hnotify is disabled so we have no notify events to ignore. ++ * when a user specified the xino, we cannot get au_hdir to be ignored. ++ */ ++ if (!wbrtop) ++ mutex_lock(&mtx); ++ file = vfsub_filp_open(fpath, O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE ++ /* | __FMODE_NONOTIFY */, ++ 0666); ++ if (IS_ERR(file)) { ++ if (!wbrtop) ++ mutex_unlock(&mtx); ++ if (!silent) ++ pr_err("open %s(%ld)\n", fpath, PTR_ERR(file)); ++ return file; ++ } ++ ++ /* keep file count */ ++ err = 0; ++ d = file->f_path.dentry; ++ h_parent = au_dget_parent_lock(d, AuLsc_I_PARENT); ++ if (!wbrtop) ++ mutex_unlock(&mtx); ++ /* mnt_want_write() is unnecessary here */ ++ h_dir = d_inode(h_parent); ++ inode = file_inode(file); ++ /* no delegation since it is just created */ ++ if (inode->i_nlink) ++ err = vfsub_unlink(h_dir, &file->f_path, /*delegated*/NULL, ++ /*force*/0); ++ inode_unlock(h_dir); ++ dput(h_parent); ++ if (unlikely(err)) { ++ if (!silent) ++ pr_err("unlink %s(%d)\n", fpath, err); ++ goto out; ++ } ++ ++ err = -EINVAL; ++ if (unlikely(sb && sb == d->d_sb)) { ++ if (!silent) ++ pr_err("%s must be outside\n", fpath); ++ goto out; ++ } ++ if (unlikely(au_test_fs_bad_xino(d->d_sb))) { ++ if (!silent) ++ pr_err("xino doesn't support %s(%s)\n", ++ fpath, au_sbtype(d->d_sb)); ++ goto out; ++ } ++ return file; /* success */ ++ ++out: ++ fput(file); ++ file = ERR_PTR(err); ++ return file; ++} ++ ++/* ++ * create a new xinofile at the same place/path as @base. ++ */ ++struct file *au_xino_create2(struct super_block *sb, struct path *base, ++ struct file *copy_src) ++{ ++ struct file *file; ++ struct dentry *dentry; ++ struct inode *dir, *delegated; ++ struct qstr *name; ++ struct path ppath, path; ++ int err, do_unlock; ++ struct au_xino_lock_dir ldir; ++ ++ do_unlock = 1; ++ au_xino_lock_dir(sb, base, &ldir); ++ dentry = base->dentry; ++ ppath.dentry = dentry->d_parent; /* dir inode is locked */ ++ ppath.mnt = base->mnt; ++ dir = d_inode(ppath.dentry); ++ IMustLock(dir); ++ ++ name = &dentry->d_name; ++ path.dentry = vfsub_lookup_one_len(name->name, &ppath, name->len); ++ if (IS_ERR(path.dentry)) { ++ file = (void *)path.dentry; ++ pr_err("%pd lookup err %ld\n", dentry, PTR_ERR(path.dentry)); ++ goto out; ++ } ++ ++ /* no need to mnt_want_write() since we call dentry_open() later */ ++ err = vfs_create(mnt_user_ns(base->mnt), dir, path.dentry, 0666, NULL); ++ if (unlikely(err)) { ++ file = ERR_PTR(err); ++ pr_err("%pd create err %d\n", dentry, err); ++ goto out_dput; ++ } ++ ++ path.mnt = base->mnt; ++ file = vfsub_dentry_open(&path, ++ O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE ++ /* | __FMODE_NONOTIFY */); ++ if (IS_ERR(file)) { ++ pr_err("%pd open err %ld\n", dentry, PTR_ERR(file)); ++ goto out_dput; ++ } ++ ++ delegated = NULL; ++ err = vfsub_unlink(dir, &file->f_path, &delegated, /*force*/0); ++ au_xino_unlock_dir(&ldir); ++ do_unlock = 0; ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ if (unlikely(err)) { ++ pr_err("%pd unlink err %d\n", dentry, err); ++ goto out_fput; ++ } ++ ++ if (copy_src) { ++ /* no one can touch copy_src xino */ ++ err = au_copy_file(file, copy_src, vfsub_f_size_read(copy_src)); ++ if (unlikely(err)) { ++ pr_err("%pd copy err %d\n", dentry, err); ++ goto out_fput; ++ } ++ } ++ goto out_dput; /* success */ ++ ++out_fput: ++ fput(file); ++ file = ERR_PTR(err); ++out_dput: ++ dput(path.dentry); ++out: ++ if (do_unlock) ++ au_xino_unlock_dir(&ldir); ++ return file; ++} ++ ++struct file *au_xino_file1(struct au_xino *xi) ++{ ++ struct file *file; ++ unsigned int u, nfile; ++ ++ file = NULL; ++ nfile = xi->xi_nfile; ++ for (u = 0; u < nfile; u++) { ++ file = xi->xi_file[u]; ++ if (file) ++ break; ++ } ++ ++ return file; ++} ++ ++static int au_xino_file_set(struct au_xino *xi, int idx, struct file *file) ++{ ++ int err; ++ struct file *f; ++ void *p; ++ ++ if (file) ++ get_file(file); ++ ++ err = 0; ++ f = NULL; ++ if (idx < xi->xi_nfile) { ++ f = xi->xi_file[idx]; ++ if (f) ++ fput(f); ++ } else { ++ p = au_kzrealloc(xi->xi_file, ++ sizeof(*xi->xi_file) * xi->xi_nfile, ++ sizeof(*xi->xi_file) * (idx + 1), ++ GFP_NOFS, /*may_shrink*/0); ++ if (p) { ++ MtxMustLock(&xi->xi_mtx); ++ xi->xi_file = p; ++ xi->xi_nfile = idx + 1; ++ } else { ++ err = -ENOMEM; ++ if (file) ++ fput(file); ++ goto out; ++ } ++ } ++ xi->xi_file[idx] = file; ++ ++out: ++ return err; ++} ++ ++/* ++ * if @xinew->xi is not set, then create new xigen file. ++ */ ++struct file *au_xi_new(struct super_block *sb, struct au_xi_new *xinew) ++{ ++ struct file *file; ++ int err; ++ ++ SiMustAnyLock(sb); ++ ++ file = au_xino_create2(sb, xinew->base, xinew->copy_src); ++ if (IS_ERR(file)) { ++ err = PTR_ERR(file); ++ pr_err("%s[%d], err %d\n", ++ xinew->xi ? "xino" : "xigen", ++ xinew->idx, err); ++ goto out; ++ } ++ ++ if (xinew->xi) ++ err = au_xino_file_set(xinew->xi, xinew->idx, file); ++ else { ++ BUG(); ++ /* todo: make xigen file an array */ ++ /* err = au_xigen_file_set(sb, xinew->idx, file); */ ++ } ++ fput(file); ++ if (unlikely(err)) ++ file = ERR_PTR(err); ++ ++out: ++ return file; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * truncate xino files ++ */ ++static int au_xino_do_trunc(struct super_block *sb, aufs_bindex_t bindex, ++ int idx, struct kstatfs *st) ++{ ++ int err; ++ blkcnt_t blocks; ++ struct file *file, *new_xino; ++ struct au_xi_new xinew = { ++ .idx = idx ++ }; ++ ++ err = 0; ++ xinew.xi = au_sbr(sb, bindex)->br_xino; ++ file = au_xino_file(xinew.xi, idx); ++ if (!file) ++ goto out; ++ ++ xinew.base = &file->f_path; ++ err = vfs_statfs(xinew.base, st); ++ if (unlikely(err)) { ++ AuErr1("statfs err %d, ignored\n", err); ++ err = 0; ++ goto out; ++ } ++ ++ blocks = file_inode(file)->i_blocks; ++ pr_info("begin truncating xino(b%d-%d), ib%llu, %llu/%llu free blks\n", ++ bindex, idx, (u64)blocks, st->f_bfree, st->f_blocks); ++ ++ xinew.copy_src = file; ++ new_xino = au_xi_new(sb, &xinew); ++ if (IS_ERR(new_xino)) { ++ err = PTR_ERR(new_xino); ++ pr_err("xino(b%d-%d), err %d, ignored\n", bindex, idx, err); ++ goto out; ++ } ++ ++ err = vfs_statfs(&new_xino->f_path, st); ++ if (!err) ++ pr_info("end truncating xino(b%d-%d), ib%llu, %llu/%llu free blks\n", ++ bindex, idx, (u64)file_inode(new_xino)->i_blocks, ++ st->f_bfree, st->f_blocks); ++ else { ++ AuErr1("statfs err %d, ignored\n", err); ++ err = 0; ++ } ++ ++out: ++ return err; ++} ++ ++int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex, int idx_begin) ++{ ++ int err, i; ++ unsigned long jiffy; ++ aufs_bindex_t bbot; ++ struct kstatfs *st; ++ struct au_branch *br; ++ struct au_xino *xi; ++ ++ err = -ENOMEM; ++ st = kmalloc(sizeof(*st), GFP_NOFS); ++ if (unlikely(!st)) ++ goto out; ++ ++ err = -EINVAL; ++ bbot = au_sbbot(sb); ++ if (unlikely(bindex < 0 || bbot < bindex)) ++ goto out_st; ++ ++ err = 0; ++ jiffy = jiffies; ++ br = au_sbr(sb, bindex); ++ xi = br->br_xino; ++ for (i = idx_begin; !err && i < xi->xi_nfile; i++) ++ err = au_xino_do_trunc(sb, bindex, i, st); ++ if (!err) ++ au_sbi(sb)->si_xino_jiffy = jiffy; ++ ++out_st: ++ au_kfree_rcu(st); ++out: ++ return err; ++} ++ ++struct xino_do_trunc_args { ++ struct super_block *sb; ++ struct au_branch *br; ++ int idx; ++}; ++ ++static void xino_do_trunc(void *_args) ++{ ++ struct xino_do_trunc_args *args = _args; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct inode *dir; ++ int err, idx; ++ aufs_bindex_t bindex; ++ ++ err = 0; ++ sb = args->sb; ++ dir = d_inode(sb->s_root); ++ br = args->br; ++ idx = args->idx; ++ ++ si_noflush_write_lock(sb); ++ ii_read_lock_parent(dir); ++ bindex = au_br_index(sb, br->br_id); ++ err = au_xino_trunc(sb, bindex, idx); ++ ii_read_unlock(dir); ++ if (unlikely(err)) ++ pr_warn("err b%d, (%d)\n", bindex, err); ++ atomic_dec(&br->br_xino->xi_truncating); ++ au_lcnt_dec(&br->br_count); ++ si_write_unlock(sb); ++ au_nwt_done(&au_sbi(sb)->si_nowait); ++ au_kfree_rcu(args); ++} ++ ++/* ++ * returns the index in the xi_file array whose corresponding file is necessary ++ * to truncate, or -1 which means no need to truncate. ++ */ ++static int xino_trunc_test(struct super_block *sb, struct au_branch *br) ++{ ++ int err; ++ unsigned int u; ++ struct kstatfs st; ++ struct au_sbinfo *sbinfo; ++ struct au_xino *xi; ++ struct file *file; ++ ++ /* todo: si_xino_expire and the ratio should be customizable */ ++ sbinfo = au_sbi(sb); ++ if (time_before(jiffies, ++ sbinfo->si_xino_jiffy + sbinfo->si_xino_expire)) ++ return -1; ++ ++ /* truncation border */ ++ xi = br->br_xino; ++ for (u = 0; u < xi->xi_nfile; u++) { ++ file = au_xino_file(xi, u); ++ if (!file) ++ continue; ++ ++ err = vfs_statfs(&file->f_path, &st); ++ if (unlikely(err)) { ++ AuErr1("statfs err %d, ignored\n", err); ++ return -1; ++ } ++ if (div64_u64(st.f_bfree * 100, st.f_blocks) ++ >= AUFS_XINO_DEF_TRUNC) ++ return u; ++ } ++ ++ return -1; ++} ++ ++static void xino_try_trunc(struct super_block *sb, struct au_branch *br) ++{ ++ int idx; ++ struct xino_do_trunc_args *args; ++ int wkq_err; ++ ++ idx = xino_trunc_test(sb, br); ++ if (idx < 0) ++ return; ++ ++ if (atomic_inc_return(&br->br_xino->xi_truncating) > 1) ++ goto out; ++ ++ /* lock and kfree() will be called in trunc_xino() */ ++ args = kmalloc(sizeof(*args), GFP_NOFS); ++ if (unlikely(!args)) { ++ AuErr1("no memory\n"); ++ goto out; ++ } ++ ++ au_lcnt_inc(&br->br_count); ++ args->sb = sb; ++ args->br = br; ++ args->idx = idx; ++ wkq_err = au_wkq_nowait(xino_do_trunc, args, sb, /*flags*/0); ++ if (!wkq_err) ++ return; /* success */ ++ ++ pr_err("wkq %d\n", wkq_err); ++ au_lcnt_dec(&br->br_count); ++ au_kfree_rcu(args); ++ ++out: ++ atomic_dec(&br->br_xino->xi_truncating); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_xi_calc { ++ int idx; ++ loff_t pos; ++}; ++ ++static void au_xi_calc(struct super_block *sb, ino_t h_ino, ++ struct au_xi_calc *calc) ++{ ++ loff_t maxent; ++ ++ maxent = au_xi_maxent(sb); ++ calc->idx = div64_u64_rem(h_ino, maxent, &calc->pos); ++ calc->pos *= sizeof(ino_t); ++} ++ ++static int au_xino_do_new_async(struct super_block *sb, struct au_branch *br, ++ struct au_xi_calc *calc) ++{ ++ int err; ++ struct file *file; ++ struct au_xino *xi = br->br_xino; ++ struct au_xi_new xinew = { ++ .xi = xi ++ }; ++ ++ SiMustAnyLock(sb); ++ ++ err = 0; ++ if (!xi) ++ goto out; ++ ++ mutex_lock(&xi->xi_mtx); ++ file = au_xino_file(xi, calc->idx); ++ if (file) ++ goto out_mtx; ++ ++ file = au_xino_file(xi, /*idx*/-1); ++ AuDebugOn(!file); ++ xinew.idx = calc->idx; ++ xinew.base = &file->f_path; ++ /* xinew.copy_src = NULL; */ ++ file = au_xi_new(sb, &xinew); ++ if (IS_ERR(file)) ++ err = PTR_ERR(file); ++ ++out_mtx: ++ mutex_unlock(&xi->xi_mtx); ++out: ++ return err; ++} ++ ++struct au_xino_do_new_async_args { ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_xi_calc calc; ++ ino_t ino; ++}; ++ ++struct au_xi_writing { ++ struct hlist_bl_node node; ++ ino_t h_ino, ino; ++}; ++ ++static int au_xino_do_write(struct file *file, struct au_xi_calc *calc, ++ ino_t ino); ++ ++static void au_xino_call_do_new_async(void *args) ++{ ++ struct au_xino_do_new_async_args *a = args; ++ struct au_branch *br; ++ struct super_block *sb; ++ struct au_sbinfo *sbi; ++ struct inode *root; ++ struct file *file; ++ struct au_xi_writing *del, *p; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ int err; ++ ++ br = a->br; ++ sb = a->sb; ++ sbi = au_sbi(sb); ++ si_noflush_read_lock(sb); ++ root = d_inode(sb->s_root); ++ ii_read_lock_child(root); ++ err = au_xino_do_new_async(sb, br, &a->calc); ++ if (unlikely(err)) { ++ AuIOErr("err %d\n", err); ++ goto out; ++ } ++ ++ file = au_xino_file(br->br_xino, a->calc.idx); ++ AuDebugOn(!file); ++ err = au_xino_do_write(file, &a->calc, a->ino); ++ if (unlikely(err)) { ++ AuIOErr("err %d\n", err); ++ goto out; ++ } ++ ++ del = NULL; ++ hbl = &br->br_xino->xi_writing; ++ hlist_bl_lock(hbl); ++ au_hbl_for_each(pos, hbl) { ++ p = container_of(pos, struct au_xi_writing, node); ++ if (p->ino == a->ino) { ++ del = p; ++ hlist_bl_del(&p->node); ++ break; ++ } ++ } ++ hlist_bl_unlock(hbl); ++ au_kfree_rcu(del); ++ ++out: ++ au_lcnt_dec(&br->br_count); ++ ii_read_unlock(root); ++ si_read_unlock(sb); ++ au_nwt_done(&sbi->si_nowait); ++ au_kfree_rcu(a); ++} ++ ++/* ++ * create a new xino file asynchronously ++ */ ++static int au_xino_new_async(struct super_block *sb, struct au_branch *br, ++ struct au_xi_calc *calc, ino_t ino) ++{ ++ int err; ++ struct au_xino_do_new_async_args *arg; ++ ++ err = -ENOMEM; ++ arg = kmalloc(sizeof(*arg), GFP_NOFS); ++ if (unlikely(!arg)) ++ goto out; ++ ++ arg->sb = sb; ++ arg->br = br; ++ arg->calc = *calc; ++ arg->ino = ino; ++ au_lcnt_inc(&br->br_count); ++ err = au_wkq_nowait(au_xino_call_do_new_async, arg, sb, AuWkq_NEST); ++ if (unlikely(err)) { ++ pr_err("wkq %d\n", err); ++ au_lcnt_dec(&br->br_count); ++ au_kfree_rcu(arg); ++ } ++ ++out: ++ return err; ++} ++ ++/* ++ * read @ino from xinofile for the specified branch{@sb, @bindex} ++ * at the position of @h_ino. ++ */ ++int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t *ino) ++{ ++ int err; ++ ssize_t sz; ++ struct au_xi_calc calc; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ struct au_xino *xi; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_xi_writing *p; ++ ++ *ino = 0; ++ if (!au_opt_test(au_mntflags(sb), XINO)) ++ return 0; /* no xino */ ++ ++ err = 0; ++ au_xi_calc(sb, h_ino, &calc); ++ xi = au_sbr(sb, bindex)->br_xino; ++ file = au_xino_file(xi, calc.idx); ++ if (!file) { ++ hbl = &xi->xi_writing; ++ hlist_bl_lock(hbl); ++ au_hbl_for_each(pos, hbl) { ++ p = container_of(pos, struct au_xi_writing, node); ++ if (p->h_ino == h_ino) { ++ AuDbg("hi%llu, i%llu, found\n", ++ (u64)p->h_ino, (u64)p->ino); ++ *ino = p->ino; ++ break; ++ } ++ } ++ hlist_bl_unlock(hbl); ++ return 0; ++ } else if (vfsub_f_size_read(file) < calc.pos + sizeof(*ino)) ++ return 0; /* no xino */ ++ ++ sbinfo = au_sbi(sb); ++ sz = xino_fread(file, ino, sizeof(*ino), &calc.pos); ++ if (sz == sizeof(*ino)) ++ return 0; /* success */ ++ ++ err = sz; ++ if (unlikely(sz >= 0)) { ++ err = -EIO; ++ AuIOErr("xino read error (%zd)\n", sz); ++ } ++ return err; ++} ++ ++static int au_xino_do_write(struct file *file, struct au_xi_calc *calc, ++ ino_t ino) ++{ ++ ssize_t sz; ++ ++ sz = xino_fwrite(file, &ino, sizeof(ino), &calc->pos); ++ if (sz == sizeof(ino)) ++ return 0; /* success */ ++ ++ AuIOErr("write failed (%zd)\n", sz); ++ return -EIO; ++} ++ ++/* ++ * write @ino to the xinofile for the specified branch{@sb, @bindex} ++ * at the position of @h_ino. ++ * even if @ino is zero, it is written to the xinofile and means no entry. ++ * if the size of the xino file on a specific filesystem exceeds the watermark, ++ * try truncating it. ++ */ ++int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t ino) ++{ ++ int err; ++ unsigned int mnt_flags; ++ struct au_xi_calc calc; ++ struct file *file; ++ struct au_branch *br; ++ struct au_xino *xi; ++ struct au_xi_writing *p; ++ ++ SiMustAnyLock(sb); ++ ++ mnt_flags = au_mntflags(sb); ++ if (!au_opt_test(mnt_flags, XINO)) ++ return 0; ++ ++ au_xi_calc(sb, h_ino, &calc); ++ br = au_sbr(sb, bindex); ++ xi = br->br_xino; ++ file = au_xino_file(xi, calc.idx); ++ if (!file) { ++ /* store the inum pair into the list */ ++ p = kmalloc(sizeof(*p), GFP_NOFS | __GFP_NOFAIL); ++ p->h_ino = h_ino; ++ p->ino = ino; ++ au_hbl_add(&p->node, &xi->xi_writing); ++ ++ /* create and write a new xino file asynchronously */ ++ err = au_xino_new_async(sb, br, &calc, ino); ++ if (!err) ++ return 0; /* success */ ++ goto out; ++ } ++ ++ err = au_xino_do_write(file, &calc, ino); ++ if (!err) { ++ br = au_sbr(sb, bindex); ++ if (au_opt_test(mnt_flags, TRUNC_XINO) ++ && au_test_fs_trunc_xino(au_br_sb(br))) ++ xino_try_trunc(sb, br); ++ return 0; /* success */ ++ } ++ ++out: ++ AuIOErr("write failed (%d)\n", err); ++ return -EIO; ++} ++ ++static ssize_t xino_fread_wkq(struct file *file, void *buf, size_t size, ++ loff_t *pos); ++ ++/* todo: unnecessary to support mmap_sem since kernel-space? */ ++ssize_t xino_fread(struct file *file, void *kbuf, size_t size, loff_t *pos) ++{ ++ ssize_t err; ++ int i; ++ const int prevent_endless = 10; ++ ++ i = 0; ++ do { ++ err = vfsub_read_k(file, kbuf, size, pos); ++ if (err == -EINTR ++ && !au_wkq_test() ++ && fatal_signal_pending(current)) { ++ err = xino_fread_wkq(file, kbuf, size, pos); ++ BUG_ON(err == -EINTR); ++ } ++ } while (i++ < prevent_endless ++ && (err == -EAGAIN || err == -EINTR)); ++ ++#if 0 /* reserved for future use */ ++ if (err > 0) ++ fsnotify_access(file->f_path.dentry); ++#endif ++ ++ return err; ++} ++ ++struct xino_fread_args { ++ ssize_t *errp; ++ struct file *file; ++ void *buf; ++ size_t size; ++ loff_t *pos; ++}; ++ ++static void call_xino_fread(void *args) ++{ ++ struct xino_fread_args *a = args; ++ *a->errp = xino_fread(a->file, a->buf, a->size, a->pos); ++} ++ ++static ssize_t xino_fread_wkq(struct file *file, void *buf, size_t size, ++ loff_t *pos) ++{ ++ ssize_t err; ++ int wkq_err; ++ struct xino_fread_args args = { ++ .errp = &err, ++ .file = file, ++ .buf = buf, ++ .size = size, ++ .pos = pos ++ }; ++ ++ wkq_err = au_wkq_wait(call_xino_fread, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ ++ return err; ++} ++ ++static ssize_t xino_fwrite_wkq(struct file *file, void *buf, size_t size, ++ loff_t *pos); ++ ++static ssize_t do_xino_fwrite(struct file *file, void *kbuf, size_t size, ++ loff_t *pos) ++{ ++ ssize_t err; ++ int i; ++ const int prevent_endless = 10; ++ ++ i = 0; ++ do { ++ err = vfsub_write_k(file, kbuf, size, pos); ++ if (err == -EINTR ++ && !au_wkq_test() ++ && fatal_signal_pending(current)) { ++ err = xino_fwrite_wkq(file, kbuf, size, pos); ++ BUG_ON(err == -EINTR); ++ } ++ } while (i++ < prevent_endless ++ && (err == -EAGAIN || err == -EINTR)); ++ ++#if 0 /* reserved for future use */ ++ if (err > 0) ++ fsnotify_modify(file->f_path.dentry); ++#endif ++ ++ return err; ++} ++ ++struct do_xino_fwrite_args { ++ ssize_t *errp; ++ struct file *file; ++ void *buf; ++ size_t size; ++ loff_t *pos; ++}; ++ ++static void call_do_xino_fwrite(void *args) ++{ ++ struct do_xino_fwrite_args *a = args; ++ *a->errp = do_xino_fwrite(a->file, a->buf, a->size, a->pos); ++} ++ ++static ssize_t xino_fwrite_wkq(struct file *file, void *buf, size_t size, ++ loff_t *pos) ++{ ++ ssize_t err; ++ int wkq_err; ++ struct do_xino_fwrite_args args = { ++ .errp = &err, ++ .file = file, ++ .buf = buf, ++ .size = size, ++ .pos = pos ++ }; ++ ++ /* ++ * it breaks RLIMIT_FSIZE and normal user's limit, ++ * users should care about quota and real 'filesystem full.' ++ */ ++ wkq_err = au_wkq_wait(call_do_xino_fwrite, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ ++ return err; ++} ++ ++ssize_t xino_fwrite(struct file *file, void *buf, size_t size, loff_t *pos) ++{ ++ ssize_t err; ++ ++ if (rlimit(RLIMIT_FSIZE) == RLIM_INFINITY) { ++ lockdep_off(); ++ err = do_xino_fwrite(file, buf, size, pos); ++ lockdep_on(); ++ } else { ++ lockdep_off(); ++ err = xino_fwrite_wkq(file, buf, size, pos); ++ lockdep_on(); ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * inode number bitmap ++ */ ++static const int page_bits = (int)PAGE_SIZE * BITS_PER_BYTE; ++static ino_t xib_calc_ino(unsigned long pindex, int bit) ++{ ++ ino_t ino; ++ ++ AuDebugOn(bit < 0 || page_bits <= bit); ++ ino = AUFS_FIRST_INO + pindex * page_bits + bit; ++ return ino; ++} ++ ++static void xib_calc_bit(ino_t ino, unsigned long *pindex, int *bit) ++{ ++ AuDebugOn(ino < AUFS_FIRST_INO); ++ ino -= AUFS_FIRST_INO; ++ *pindex = ino / page_bits; ++ *bit = ino % page_bits; ++} ++ ++static int xib_pindex(struct super_block *sb, unsigned long pindex) ++{ ++ int err; ++ loff_t pos; ++ ssize_t sz; ++ struct au_sbinfo *sbinfo; ++ struct file *xib; ++ unsigned long *p; ++ ++ sbinfo = au_sbi(sb); ++ MtxMustLock(&sbinfo->si_xib_mtx); ++ AuDebugOn(pindex > ULONG_MAX / PAGE_SIZE ++ || !au_opt_test(sbinfo->si_mntflags, XINO)); ++ ++ if (pindex == sbinfo->si_xib_last_pindex) ++ return 0; ++ ++ xib = sbinfo->si_xib; ++ p = sbinfo->si_xib_buf; ++ pos = sbinfo->si_xib_last_pindex; ++ pos *= PAGE_SIZE; ++ sz = xino_fwrite(xib, p, PAGE_SIZE, &pos); ++ if (unlikely(sz != PAGE_SIZE)) ++ goto out; ++ ++ pos = pindex; ++ pos *= PAGE_SIZE; ++ if (vfsub_f_size_read(xib) >= pos + PAGE_SIZE) ++ sz = xino_fread(xib, p, PAGE_SIZE, &pos); ++ else { ++ memset(p, 0, PAGE_SIZE); ++ sz = xino_fwrite(xib, p, PAGE_SIZE, &pos); ++ } ++ if (sz == PAGE_SIZE) { ++ sbinfo->si_xib_last_pindex = pindex; ++ return 0; /* success */ ++ } ++ ++out: ++ AuIOErr1("write failed (%zd)\n", sz); ++ err = sz; ++ if (sz >= 0) ++ err = -EIO; ++ return err; ++} ++ ++static void au_xib_clear_bit(struct inode *inode) ++{ ++ int err, bit; ++ unsigned long pindex; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ ++ AuDebugOn(inode->i_nlink); ++ ++ sb = inode->i_sb; ++ xib_calc_bit(inode->i_ino, &pindex, &bit); ++ AuDebugOn(page_bits <= bit); ++ sbinfo = au_sbi(sb); ++ mutex_lock(&sbinfo->si_xib_mtx); ++ err = xib_pindex(sb, pindex); ++ if (!err) { ++ clear_bit(bit, sbinfo->si_xib_buf); ++ sbinfo->si_xib_next_bit = bit; ++ } ++ mutex_unlock(&sbinfo->si_xib_mtx); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * truncate a xino bitmap file ++ */ ++ ++/* todo: slow */ ++static int do_xib_restore(struct super_block *sb, struct file *file, void *page) ++{ ++ int err, bit; ++ ssize_t sz; ++ unsigned long pindex; ++ loff_t pos, pend; ++ struct au_sbinfo *sbinfo; ++ ino_t *ino; ++ unsigned long *p; ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ MtxMustLock(&sbinfo->si_xib_mtx); ++ p = sbinfo->si_xib_buf; ++ pend = vfsub_f_size_read(file); ++ pos = 0; ++ while (pos < pend) { ++ sz = xino_fread(file, page, PAGE_SIZE, &pos); ++ err = sz; ++ if (unlikely(sz <= 0)) ++ goto out; ++ ++ err = 0; ++ for (ino = page; sz > 0; ino++, sz -= sizeof(ino)) { ++ if (unlikely(*ino < AUFS_FIRST_INO)) ++ continue; ++ ++ xib_calc_bit(*ino, &pindex, &bit); ++ AuDebugOn(page_bits <= bit); ++ err = xib_pindex(sb, pindex); ++ if (!err) ++ set_bit(bit, p); ++ else ++ goto out; ++ } ++ } ++ ++out: ++ return err; ++} ++ ++static int xib_restore(struct super_block *sb) ++{ ++ int err, i; ++ unsigned int nfile; ++ aufs_bindex_t bindex, bbot; ++ void *page; ++ struct au_branch *br; ++ struct au_xino *xi; ++ struct file *file; ++ ++ err = -ENOMEM; ++ page = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!page)) ++ goto out; ++ ++ err = 0; ++ bbot = au_sbbot(sb); ++ for (bindex = 0; !err && bindex <= bbot; bindex++) ++ if (!bindex || is_sb_shared(sb, bindex, bindex - 1) < 0) { ++ br = au_sbr(sb, bindex); ++ xi = br->br_xino; ++ nfile = xi->xi_nfile; ++ for (i = 0; i < nfile; i++) { ++ file = au_xino_file(xi, i); ++ if (file) ++ err = do_xib_restore(sb, file, page); ++ } ++ } else ++ AuDbg("skip shared b%d\n", bindex); ++ free_page((unsigned long)page); ++ ++out: ++ return err; ++} ++ ++int au_xib_trunc(struct super_block *sb) ++{ ++ int err; ++ ssize_t sz; ++ loff_t pos; ++ struct au_sbinfo *sbinfo; ++ unsigned long *p; ++ struct file *file; ++ ++ SiMustWriteLock(sb); ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ if (!au_opt_test(sbinfo->si_mntflags, XINO)) ++ goto out; ++ ++ file = sbinfo->si_xib; ++ if (vfsub_f_size_read(file) <= PAGE_SIZE) ++ goto out; ++ ++ file = au_xino_create2(sb, &sbinfo->si_xib->f_path, NULL); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ fput(sbinfo->si_xib); ++ sbinfo->si_xib = file; ++ ++ p = sbinfo->si_xib_buf; ++ memset(p, 0, PAGE_SIZE); ++ pos = 0; ++ sz = xino_fwrite(sbinfo->si_xib, p, PAGE_SIZE, &pos); ++ if (unlikely(sz != PAGE_SIZE)) { ++ err = sz; ++ AuIOErr("err %d\n", err); ++ if (sz >= 0) ++ err = -EIO; ++ goto out; ++ } ++ ++ mutex_lock(&sbinfo->si_xib_mtx); ++ /* mnt_want_write() is unnecessary here */ ++ err = xib_restore(sb); ++ mutex_unlock(&sbinfo->si_xib_mtx); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_xino *au_xino_alloc(unsigned int nfile) ++{ ++ struct au_xino *xi; ++ ++ xi = kzalloc(sizeof(*xi), GFP_NOFS); ++ if (unlikely(!xi)) ++ goto out; ++ xi->xi_nfile = nfile; ++ xi->xi_file = kcalloc(nfile, sizeof(*xi->xi_file), GFP_NOFS); ++ if (unlikely(!xi->xi_file)) ++ goto out_free; ++ ++ xi->xi_nondir.total = 8; /* initial size */ ++ xi->xi_nondir.array = kcalloc(xi->xi_nondir.total, sizeof(ino_t), ++ GFP_NOFS); ++ if (unlikely(!xi->xi_nondir.array)) ++ goto out_file; ++ ++ spin_lock_init(&xi->xi_nondir.spin); ++ init_waitqueue_head(&xi->xi_nondir.wqh); ++ mutex_init(&xi->xi_mtx); ++ INIT_HLIST_BL_HEAD(&xi->xi_writing); ++ atomic_set(&xi->xi_truncating, 0); ++ kref_init(&xi->xi_kref); ++ goto out; /* success */ ++ ++out_file: ++ au_kfree_try_rcu(xi->xi_file); ++out_free: ++ au_kfree_rcu(xi); ++ xi = NULL; ++out: ++ return xi; ++} ++ ++static int au_xino_init(struct au_branch *br, int idx, struct file *file) ++{ ++ int err; ++ struct au_xino *xi; ++ ++ err = 0; ++ xi = au_xino_alloc(idx + 1); ++ if (unlikely(!xi)) { ++ err = -ENOMEM; ++ goto out; ++ } ++ ++ if (file) ++ get_file(file); ++ xi->xi_file[idx] = file; ++ AuDebugOn(br->br_xino); ++ br->br_xino = xi; ++ ++out: ++ return err; ++} ++ ++static void au_xino_release(struct kref *kref) ++{ ++ struct au_xino *xi; ++ int i; ++ unsigned long ul; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos, *n; ++ struct au_xi_writing *p; ++ ++ xi = container_of(kref, struct au_xino, xi_kref); ++ for (i = 0; i < xi->xi_nfile; i++) ++ if (xi->xi_file[i]) ++ fput(xi->xi_file[i]); ++ for (i = xi->xi_nondir.total - 1; i >= 0; i--) ++ AuDebugOn(xi->xi_nondir.array[i]); ++ mutex_destroy(&xi->xi_mtx); ++ hbl = &xi->xi_writing; ++ ul = au_hbl_count(hbl); ++ if (unlikely(ul)) { ++ pr_warn("xi_writing %lu\n", ul); ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry_safe(p, pos, n, hbl, node) { ++ hlist_bl_del(&p->node); ++ /* kmemleak reported au_kfree_rcu() doesn't free it */ ++ kfree(p); ++ } ++ hlist_bl_unlock(hbl); ++ } ++ au_kfree_try_rcu(xi->xi_file); ++ au_kfree_try_rcu(xi->xi_nondir.array); ++ au_kfree_rcu(xi); ++} ++ ++int au_xino_put(struct au_branch *br) ++{ ++ int ret; ++ struct au_xino *xi; ++ ++ ret = 0; ++ xi = br->br_xino; ++ if (xi) { ++ br->br_xino = NULL; ++ ret = kref_put(&xi->xi_kref, au_xino_release); ++ } ++ ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * xino mount option handlers ++ */ ++ ++/* xino bitmap */ ++static void xino_clear_xib(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ if (sbinfo->si_xib) ++ fput(sbinfo->si_xib); ++ sbinfo->si_xib = NULL; ++ if (sbinfo->si_xib_buf) ++ free_page((unsigned long)sbinfo->si_xib_buf); ++ sbinfo->si_xib_buf = NULL; ++} ++ ++static int au_xino_set_xib(struct super_block *sb, struct path *path) ++{ ++ int err; ++ loff_t pos; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ struct super_block *xi_sb; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ file = au_xino_create2(sb, path, sbinfo->si_xib); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ if (sbinfo->si_xib) ++ fput(sbinfo->si_xib); ++ sbinfo->si_xib = file; ++ xi_sb = file_inode(file)->i_sb; ++ sbinfo->si_ximaxent = xi_sb->s_maxbytes; ++ if (unlikely(sbinfo->si_ximaxent < PAGE_SIZE)) { ++ err = -EIO; ++ pr_err("s_maxbytes(%llu) on %s is too small\n", ++ (u64)sbinfo->si_ximaxent, au_sbtype(xi_sb)); ++ goto out_unset; ++ } ++ sbinfo->si_ximaxent /= sizeof(ino_t); ++ ++ err = -ENOMEM; ++ if (!sbinfo->si_xib_buf) ++ sbinfo->si_xib_buf = (void *)get_zeroed_page(GFP_NOFS); ++ if (unlikely(!sbinfo->si_xib_buf)) ++ goto out_unset; ++ ++ sbinfo->si_xib_last_pindex = 0; ++ sbinfo->si_xib_next_bit = 0; ++ if (vfsub_f_size_read(file) < PAGE_SIZE) { ++ pos = 0; ++ err = xino_fwrite(file, sbinfo->si_xib_buf, PAGE_SIZE, &pos); ++ if (unlikely(err != PAGE_SIZE)) ++ goto out_free; ++ } ++ err = 0; ++ goto out; /* success */ ++ ++out_free: ++ if (sbinfo->si_xib_buf) ++ free_page((unsigned long)sbinfo->si_xib_buf); ++ sbinfo->si_xib_buf = NULL; ++ if (err >= 0) ++ err = -EIO; ++out_unset: ++ fput(sbinfo->si_xib); ++ sbinfo->si_xib = NULL; ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* xino for each branch */ ++static void xino_clear_br(struct super_block *sb) ++{ ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ AuDebugOn(!br); ++ au_xino_put(br); ++ } ++} ++ ++static void au_xino_set_br_shared(struct super_block *sb, struct au_branch *br, ++ aufs_bindex_t bshared) ++{ ++ struct au_branch *brshared; ++ ++ brshared = au_sbr(sb, bshared); ++ AuDebugOn(!brshared->br_xino); ++ AuDebugOn(!brshared->br_xino->xi_file); ++ if (br->br_xino != brshared->br_xino) { ++ au_xino_get(brshared); ++ au_xino_put(br); ++ br->br_xino = brshared->br_xino; ++ } ++} ++ ++struct au_xino_do_set_br { ++ struct au_branch *br; ++ ino_t h_ino; ++ aufs_bindex_t bshared; ++}; ++ ++static int au_xino_do_set_br(struct super_block *sb, struct path *path, ++ struct au_xino_do_set_br *args) ++{ ++ int err; ++ struct au_xi_calc calc; ++ struct file *file; ++ struct au_branch *br; ++ struct au_xi_new xinew = { ++ .base = path ++ }; ++ ++ br = args->br; ++ xinew.xi = br->br_xino; ++ au_xi_calc(sb, args->h_ino, &calc); ++ xinew.copy_src = au_xino_file(xinew.xi, calc.idx); ++ if (args->bshared >= 0) ++ /* shared xino */ ++ au_xino_set_br_shared(sb, br, args->bshared); ++ else if (!xinew.xi) { ++ /* new xino */ ++ err = au_xino_init(br, calc.idx, xinew.copy_src); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ /* force re-creating */ ++ xinew.xi = br->br_xino; ++ xinew.idx = calc.idx; ++ mutex_lock(&xinew.xi->xi_mtx); ++ file = au_xi_new(sb, &xinew); ++ mutex_unlock(&xinew.xi->xi_mtx); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ AuDebugOn(!file); ++ ++ err = au_xino_do_write(file, &calc, AUFS_ROOT_INO); ++ if (unlikely(err)) ++ au_xino_put(br); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_xino_set_br(struct super_block *sb, struct path *path) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct au_xino_do_set_br args; ++ struct inode *inode; ++ ++ SiMustWriteLock(sb); ++ ++ bbot = au_sbbot(sb); ++ inode = d_inode(sb->s_root); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ args.h_ino = au_h_iptr(inode, bindex)->i_ino; ++ args.br = au_sbr(sb, bindex); ++ args.bshared = is_sb_shared(sb, bindex, bindex - 1); ++ err = au_xino_do_set_br(sb, path, &args); ++ if (unlikely(err)) ++ break; ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_xino_clr(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ au_xigen_clr(sb); ++ xino_clear_xib(sb); ++ xino_clear_br(sb); ++ dbgaufs_brs_del(sb, 0); ++ sbinfo = au_sbi(sb); ++ /* lvalue, do not call au_mntflags() */ ++ au_opt_clr(sbinfo->si_mntflags, XINO); ++} ++ ++int au_xino_set(struct super_block *sb, struct au_opt_xino *xiopt, int remount) ++{ ++ int err, skip; ++ struct dentry *dentry, *parent, *cur_dentry, *cur_parent; ++ struct qstr *dname, *cur_name; ++ struct file *cur_xino; ++ struct au_sbinfo *sbinfo; ++ struct path *path, *cur_path; ++ ++ SiMustWriteLock(sb); ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ path = &xiopt->file->f_path; ++ dentry = path->dentry; ++ parent = dget_parent(dentry); ++ if (remount) { ++ skip = 0; ++ cur_xino = sbinfo->si_xib; ++ if (cur_xino) { ++ cur_path = &cur_xino->f_path; ++ cur_dentry = cur_path->dentry; ++ cur_parent = dget_parent(cur_dentry); ++ cur_name = &cur_dentry->d_name; ++ dname = &dentry->d_name; ++ skip = (cur_parent == parent ++ && au_qstreq(dname, cur_name)); ++ dput(cur_parent); ++ } ++ if (skip) ++ goto out; ++ } ++ ++ au_opt_set(sbinfo->si_mntflags, XINO); ++ err = au_xino_set_xib(sb, path); ++ /* si_x{read,write} are set */ ++ if (!err) ++ err = au_xigen_set(sb, path); ++ if (!err) ++ err = au_xino_set_br(sb, path); ++ if (!err) { ++ dbgaufs_brs_add(sb, 0, /*topdown*/1); ++ goto out; /* success */ ++ } ++ ++ /* reset all */ ++ AuIOErr("failed setting xino(%d).\n", err); ++ au_xino_clr(sb); ++ ++out: ++ dput(parent); ++ return err; ++} ++ ++/* ++ * create a xinofile at the default place/path. ++ */ ++struct file *au_xino_def(struct super_block *sb) ++{ ++ struct file *file; ++ char *page, *p; ++ struct au_branch *br; ++ struct super_block *h_sb; ++ struct path path; ++ aufs_bindex_t bbot, bindex, bwr; ++ ++ br = NULL; ++ bbot = au_sbbot(sb); ++ bwr = -1; ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_writable(br->br_perm) ++ && !au_test_fs_bad_xino(au_br_sb(br))) { ++ bwr = bindex; ++ break; ++ } ++ } ++ ++ if (bwr >= 0) { ++ file = ERR_PTR(-ENOMEM); ++ page = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!page)) ++ goto out; ++ path.mnt = au_br_mnt(br); ++ path.dentry = au_h_dptr(sb->s_root, bwr); ++ p = d_path(&path, page, PATH_MAX - sizeof(AUFS_XINO_FNAME)); ++ file = (void *)p; ++ if (!IS_ERR(p)) { ++ strcat(p, "/" AUFS_XINO_FNAME); ++ AuDbg("%s\n", p); ++ file = au_xino_create(sb, p, /*silent*/0, /*wbrtop*/1); ++ } ++ free_page((unsigned long)page); ++ } else { ++ file = au_xino_create(sb, AUFS_XINO_DEFPATH, /*silent*/0, ++ /*wbrtop*/0); ++ if (IS_ERR(file)) ++ goto out; ++ h_sb = file->f_path.dentry->d_sb; ++ if (unlikely(au_test_fs_bad_xino(h_sb))) { ++ pr_err("xino doesn't support %s(%s)\n", ++ AUFS_XINO_DEFPATH, au_sbtype(h_sb)); ++ fput(file); ++ file = ERR_PTR(-EINVAL); ++ } ++ } ++ ++out: ++ return file; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * initialize the xinofile for the specified branch @br ++ * at the place/path where @base_file indicates. ++ * test whether another branch is on the same filesystem or not, ++ * if found then share the xinofile with another branch. ++ */ ++int au_xino_init_br(struct super_block *sb, struct au_branch *br, ino_t h_ino, ++ struct path *base) ++{ ++ int err; ++ struct au_xino_do_set_br args = { ++ .h_ino = h_ino, ++ .br = br ++ }; ++ ++ args.bshared = sbr_find_shared(sb, /*btop*/0, au_sbbot(sb), ++ au_br_sb(br)); ++ err = au_xino_do_set_br(sb, base, &args); ++ if (unlikely(err)) ++ au_xino_put(br); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * get an unused inode number from bitmap ++ */ ++ino_t au_xino_new_ino(struct super_block *sb) ++{ ++ ino_t ino; ++ unsigned long *p, pindex, ul, pend; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ int free_bit, err; ++ ++ if (!au_opt_test(au_mntflags(sb), XINO)) ++ return iunique(sb, AUFS_FIRST_INO); ++ ++ sbinfo = au_sbi(sb); ++ mutex_lock(&sbinfo->si_xib_mtx); ++ p = sbinfo->si_xib_buf; ++ free_bit = sbinfo->si_xib_next_bit; ++ if (free_bit < page_bits && !test_bit(free_bit, p)) ++ goto out; /* success */ ++ free_bit = find_first_zero_bit(p, page_bits); ++ if (free_bit < page_bits) ++ goto out; /* success */ ++ ++ pindex = sbinfo->si_xib_last_pindex; ++ for (ul = pindex - 1; ul < ULONG_MAX; ul--) { ++ err = xib_pindex(sb, ul); ++ if (unlikely(err)) ++ goto out_err; ++ free_bit = find_first_zero_bit(p, page_bits); ++ if (free_bit < page_bits) ++ goto out; /* success */ ++ } ++ ++ file = sbinfo->si_xib; ++ pend = vfsub_f_size_read(file) / PAGE_SIZE; ++ for (ul = pindex + 1; ul <= pend; ul++) { ++ err = xib_pindex(sb, ul); ++ if (unlikely(err)) ++ goto out_err; ++ free_bit = find_first_zero_bit(p, page_bits); ++ if (free_bit < page_bits) ++ goto out; /* success */ ++ } ++ BUG(); ++ ++out: ++ set_bit(free_bit, p); ++ sbinfo->si_xib_next_bit = free_bit + 1; ++ pindex = sbinfo->si_xib_last_pindex; ++ mutex_unlock(&sbinfo->si_xib_mtx); ++ ino = xib_calc_ino(pindex, free_bit); ++ AuDbg("i%lu\n", (unsigned long)ino); ++ return ino; ++out_err: ++ mutex_unlock(&sbinfo->si_xib_mtx); ++ AuDbg("i0\n"); ++ return 0; ++} ++ ++/* for s_op->delete_inode() */ ++void au_xino_delete_inode(struct inode *inode, const int unlinked) ++{ ++ int err; ++ unsigned int mnt_flags; ++ aufs_bindex_t bindex, bbot, bi; ++ unsigned char try_trunc; ++ struct au_iinfo *iinfo; ++ struct super_block *sb; ++ struct au_hinode *hi; ++ struct inode *h_inode; ++ struct au_branch *br; ++ struct au_xi_calc calc; ++ struct file *file; ++ ++ AuDebugOn(au_is_bad_inode(inode)); ++ ++ sb = inode->i_sb; ++ mnt_flags = au_mntflags(sb); ++ if (!au_opt_test(mnt_flags, XINO) ++ || inode->i_ino == AUFS_ROOT_INO) ++ return; ++ ++ if (unlinked) { ++ au_xigen_inc(inode); ++ au_xib_clear_bit(inode); ++ } ++ ++ iinfo = au_ii(inode); ++ bindex = iinfo->ii_btop; ++ if (bindex < 0) ++ return; ++ ++ try_trunc = !!au_opt_test(mnt_flags, TRUNC_XINO); ++ hi = au_hinode(iinfo, bindex); ++ bbot = iinfo->ii_bbot; ++ for (; bindex <= bbot; bindex++, hi++) { ++ h_inode = hi->hi_inode; ++ if (!h_inode ++ || (!unlinked && h_inode->i_nlink)) ++ continue; ++ ++ /* inode may not be revalidated */ ++ bi = au_br_index(sb, hi->hi_id); ++ if (bi < 0) ++ continue; ++ ++ br = au_sbr(sb, bi); ++ au_xi_calc(sb, h_inode->i_ino, &calc); ++ file = au_xino_file(br->br_xino, calc.idx); ++ if (IS_ERR_OR_NULL(file)) ++ continue; ++ ++ err = au_xino_do_write(file, &calc, /*ino*/0); ++ if (!err && try_trunc ++ && au_test_fs_trunc_xino(au_br_sb(br))) ++ xino_try_trunc(sb, br); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_xinondir_find(struct au_xino *xi, ino_t h_ino) ++{ ++ int found, total, i; ++ ++ found = -1; ++ total = xi->xi_nondir.total; ++ for (i = 0; i < total; i++) { ++ if (xi->xi_nondir.array[i] != h_ino) ++ continue; ++ found = i; ++ break; ++ } ++ ++ return found; ++} ++ ++static int au_xinondir_expand(struct au_xino *xi) ++{ ++ int err, sz; ++ ino_t *p; ++ ++ BUILD_BUG_ON(KMALLOC_MAX_SIZE > INT_MAX); ++ ++ err = -ENOMEM; ++ sz = xi->xi_nondir.total * sizeof(ino_t); ++ if (unlikely(sz > KMALLOC_MAX_SIZE / 2)) ++ goto out; ++ p = au_kzrealloc(xi->xi_nondir.array, sz, sz << 1, GFP_ATOMIC, ++ /*may_shrink*/0); ++ if (p) { ++ xi->xi_nondir.array = p; ++ xi->xi_nondir.total <<= 1; ++ AuDbg("xi_nondir.total %d\n", xi->xi_nondir.total); ++ err = 0; ++ } ++ ++out: ++ return err; ++} ++ ++void au_xinondir_leave(struct super_block *sb, aufs_bindex_t bindex, ++ ino_t h_ino, int idx) ++{ ++ struct au_xino *xi; ++ ++ AuDebugOn(!au_opt_test(au_mntflags(sb), XINO)); ++ xi = au_sbr(sb, bindex)->br_xino; ++ AuDebugOn(idx < 0 || xi->xi_nondir.total <= idx); ++ ++ spin_lock(&xi->xi_nondir.spin); ++ AuDebugOn(xi->xi_nondir.array[idx] != h_ino); ++ xi->xi_nondir.array[idx] = 0; ++ spin_unlock(&xi->xi_nondir.spin); ++ wake_up_all(&xi->xi_nondir.wqh); ++} ++ ++int au_xinondir_enter(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ int *idx) ++{ ++ int err, found, empty; ++ struct au_xino *xi; ++ ++ err = 0; ++ *idx = -1; ++ if (!au_opt_test(au_mntflags(sb), XINO)) ++ goto out; /* no xino */ ++ ++ xi = au_sbr(sb, bindex)->br_xino; ++ ++again: ++ spin_lock(&xi->xi_nondir.spin); ++ found = au_xinondir_find(xi, h_ino); ++ if (found == -1) { ++ empty = au_xinondir_find(xi, /*h_ino*/0); ++ if (empty == -1) { ++ empty = xi->xi_nondir.total; ++ err = au_xinondir_expand(xi); ++ if (unlikely(err)) ++ goto out_unlock; ++ } ++ xi->xi_nondir.array[empty] = h_ino; ++ *idx = empty; ++ } else { ++ spin_unlock(&xi->xi_nondir.spin); ++ wait_event(xi->xi_nondir.wqh, ++ xi->xi_nondir.array[found] != h_ino); ++ goto again; ++ } ++ ++out_unlock: ++ spin_unlock(&xi->xi_nondir.spin); ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_xino_path(struct seq_file *seq, struct file *file) ++{ ++ int err; ++ ++ err = au_seq_path(seq, &file->f_path); ++ if (unlikely(err)) ++ goto out; ++ ++#define Deleted "\\040(deleted)" ++ seq->count -= sizeof(Deleted) - 1; ++ AuDebugOn(memcmp(seq->buf + seq->count, Deleted, ++ sizeof(Deleted) - 1)); ++#undef Deleted ++ ++out: ++ return err; ++} +diff -Nurp linux-5.15.37/fs/dcache.c linux-5.15.37-aufs/fs/dcache.c +--- linux-5.15.37/fs/dcache.c 2022-03-20 22:14:17.000000000 +0200 ++++ linux-5.15.37-aufs/fs/dcache.c 2022-04-08 20:22:30.617616719 +0300 +@@ -1345,7 +1345,7 @@ enum d_walk_ret { + * + * The @enter() callbacks are called with d_lock held. + */ +-static void d_walk(struct dentry *parent, void *data, ++void d_walk(struct dentry *parent, void *data, + enum d_walk_ret (*enter)(void *, struct dentry *)) + { + struct dentry *this_parent; +diff -Nurp linux-5.15.37/fs/fcntl.c linux-5.15.37-aufs/fs/fcntl.c +--- linux-5.15.37/fs/fcntl.c 2022-03-20 22:14:17.000000000 +0200 ++++ linux-5.15.37-aufs/fs/fcntl.c 2022-04-08 20:22:30.617616719 +0300 +@@ -33,7 +33,7 @@ + + #define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT | O_NOATIME) + +-static int setfl(int fd, struct file * filp, unsigned long arg) ++int setfl(int fd, struct file *filp, unsigned long arg) + { + struct inode * inode = file_inode(filp); + int error = 0; +@@ -64,6 +64,8 @@ static int setfl(int fd, struct file * f + + if (filp->f_op->check_flags) + error = filp->f_op->check_flags(arg); ++ if (!error && filp->f_op->setfl) ++ error = filp->f_op->setfl(filp, arg); + if (error) + return error; + +diff -Nurp linux-5.15.37/fs/Kconfig linux-5.15.37-aufs/fs/Kconfig +--- linux-5.15.37/fs/Kconfig 2022-03-20 22:14:17.000000000 +0200 ++++ linux-5.15.37-aufs/fs/Kconfig 2022-04-08 20:22:30.610616377 +0300 +@@ -312,6 +312,7 @@ source "fs/sysv/Kconfig" + source "fs/ufs/Kconfig" + source "fs/erofs/Kconfig" + source "fs/vboxsf/Kconfig" ++source "fs/aufs/Kconfig" + + endif # MISC_FILESYSTEMS + +diff -Nurp linux-5.15.37/fs/Makefile linux-5.15.37-aufs/fs/Makefile +--- linux-5.15.37/fs/Makefile 2022-03-20 22:14:17.000000000 +0200 ++++ linux-5.15.37-aufs/fs/Makefile 2022-04-08 20:22:30.610616377 +0300 +@@ -140,3 +140,4 @@ obj-$(CONFIG_EFIVAR_FS) += efivarfs/ + obj-$(CONFIG_EROFS_FS) += erofs/ + obj-$(CONFIG_VBOXSF_FS) += vboxsf/ + obj-$(CONFIG_ZONEFS_FS) += zonefs/ ++obj-$(CONFIG_AUFS_FS) += aufs/ +diff -Nurp linux-5.15.37/fs/namespace.c linux-5.15.37-aufs/fs/namespace.c +--- linux-5.15.37/fs/namespace.c 2022-03-20 22:14:17.000000000 +0200 ++++ linux-5.15.37-aufs/fs/namespace.c 2022-04-08 20:22:30.617616719 +0300 +@@ -839,6 +839,12 @@ static inline int check_mnt(struct mount + return mnt->mnt_ns == current->nsproxy->mnt_ns; + } + ++/* for aufs, CONFIG_AUFS_BR_FUSE */ ++int is_current_mnt_ns(struct vfsmount *mnt) ++{ ++ return check_mnt(real_mount(mnt)); ++} ++ + /* + * vfsmount lock must be held for write + */ +diff -Nurp linux-5.15.37/fs/proc/base.c linux-5.15.37-aufs/fs/proc/base.c +--- linux-5.15.37/fs/proc/base.c 2022-03-20 22:14:17.000000000 +0200 ++++ linux-5.15.37-aufs/fs/proc/base.c 2022-04-08 20:22:30.617616719 +0300 +@@ -2191,7 +2191,7 @@ static int map_files_get_link(struct den + rc = -ENOENT; + vma = find_exact_vma(mm, vm_start, vm_end); + if (vma && vma->vm_file) { +- *path = vma->vm_file->f_path; ++ *path = vma_pr_or_file(vma)->f_path; + path_get(path); + rc = 0; + } +diff -Nurp linux-5.15.37/fs/proc/nommu.c linux-5.15.37-aufs/fs/proc/nommu.c +--- linux-5.15.37/fs/proc/nommu.c 2022-03-20 22:14:17.000000000 +0200 ++++ linux-5.15.37-aufs/fs/proc/nommu.c 2022-04-08 20:22:30.617616719 +0300 +@@ -40,7 +40,10 @@ static int nommu_region_show(struct seq_ + file = region->vm_file; + + if (file) { +- struct inode *inode = file_inode(region->vm_file); ++ struct inode *inode; ++ ++ file = vmr_pr_or_file(region); ++ inode = file_inode(file); + dev = inode->i_sb->s_dev; + ino = inode->i_ino; + } +diff -Nurp linux-5.15.37/fs/proc/task_mmu.c linux-5.15.37-aufs/fs/proc/task_mmu.c +--- linux-5.15.37/fs/proc/task_mmu.c 2022-03-20 22:14:17.000000000 +0200 ++++ linux-5.15.37-aufs/fs/proc/task_mmu.c 2022-04-08 20:22:30.617616719 +0300 +@@ -281,7 +281,10 @@ show_map_vma(struct seq_file *m, struct + const char *name = NULL; + + if (file) { +- struct inode *inode = file_inode(vma->vm_file); ++ struct inode *inode; ++ ++ file = vma_pr_or_file(vma); ++ inode = file_inode(file); + dev = inode->i_sb->s_dev; + ino = inode->i_ino; + pgoff = ((loff_t)vma->vm_pgoff) << PAGE_SHIFT; +@@ -1903,7 +1906,7 @@ static int show_numa_map(struct seq_file + struct proc_maps_private *proc_priv = &numa_priv->proc_maps; + struct vm_area_struct *vma = v; + struct numa_maps *md = &numa_priv->md; +- struct file *file = vma->vm_file; ++ struct file *file = vma_pr_or_file(vma); + struct mm_struct *mm = vma->vm_mm; + struct mempolicy *pol; + char buffer[64]; +diff -Nurp linux-5.15.37/fs/proc/task_nommu.c linux-5.15.37-aufs/fs/proc/task_nommu.c +--- linux-5.15.37/fs/proc/task_nommu.c 2022-03-20 22:14:17.000000000 +0200 ++++ linux-5.15.37-aufs/fs/proc/task_nommu.c 2022-04-08 20:22:30.617616719 +0300 +@@ -155,7 +155,10 @@ static int nommu_vma_show(struct seq_fil + file = vma->vm_file; + + if (file) { +- struct inode *inode = file_inode(vma->vm_file); ++ struct inode *inode; ++ ++ file = vma_pr_or_file(vma); ++ inode = file_inode(file); + dev = inode->i_sb->s_dev; + ino = inode->i_ino; + pgoff = (loff_t)vma->vm_pgoff << PAGE_SHIFT; +diff -Nurp linux-5.15.37/fs/splice.c linux-5.15.37-aufs/fs/splice.c +--- linux-5.15.37/fs/splice.c 2022-03-20 22:14:17.000000000 +0200 ++++ linux-5.15.37-aufs/fs/splice.c 2022-04-08 20:22:30.617616719 +0300 +@@ -759,8 +759,8 @@ static int warn_unsupported(struct file + /* + * Attempt to initiate a splice from pipe to file. + */ +-static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, +- loff_t *ppos, size_t len, unsigned int flags) ++long do_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags) + { + if (unlikely(!out->f_op->splice_write)) + return warn_unsupported(out, "write"); +@@ -770,9 +770,9 @@ static long do_splice_from(struct pipe_i + /* + * Attempt to initiate a splice from a file to a pipe. + */ +-static long do_splice_to(struct file *in, loff_t *ppos, +- struct pipe_inode_info *pipe, size_t len, +- unsigned int flags) ++long do_splice_to(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags) + { + unsigned int p_space; + int ret; +diff -Nurp linux-5.15.37/include/linux/fs.h linux-5.15.37-aufs/include/linux/fs.h +--- linux-5.15.37/include/linux/fs.h 2022-03-20 22:14:17.000000000 +0200 ++++ linux-5.15.37-aufs/include/linux/fs.h 2022-04-08 20:22:30.617616719 +0300 +@@ -1372,6 +1372,7 @@ extern void fasync_free(struct fasync_st + /* can be called from interrupts */ + extern void kill_fasync(struct fasync_struct **, int, int); + ++extern int setfl(int fd, struct file *filp, unsigned long arg); + extern void __f_setown(struct file *filp, struct pid *, enum pid_type, int force); + extern int f_setown(struct file *filp, unsigned long arg, int force); + extern void f_delown(struct file *filp); +@@ -2003,6 +2004,7 @@ struct file_operations { + ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); + unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); + int (*check_flags)(int); ++ int (*setfl)(struct file *, unsigned long); + int (*flock) (struct file *, int, struct file_lock *); + ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); + ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); +@@ -2529,6 +2531,7 @@ extern int current_umask(void); + extern void ihold(struct inode * inode); + extern void iput(struct inode *); + extern int generic_update_time(struct inode *, struct timespec64 *, int); ++extern int update_time(struct inode *, struct timespec64 *, int); + + /* /sys/fs */ + extern struct kobject *fs_kobj; +@@ -2707,6 +2710,7 @@ static inline bool sb_is_blkdev_sb(struc + } + + void emergency_thaw_all(void); ++extern int __sync_filesystem(struct super_block *, int); + extern int sync_filesystem(struct super_block *); + extern const struct file_operations def_blk_fops; + extern const struct file_operations def_chr_fops; +diff -Nurp linux-5.15.37/include/linux/lockdep.h linux-5.15.37-aufs/include/linux/lockdep.h +--- linux-5.15.37/include/linux/lockdep.h 2022-03-20 22:14:17.000000000 +0200 ++++ linux-5.15.37-aufs/include/linux/lockdep.h 2022-04-08 20:22:30.618616768 +0300 +@@ -248,6 +248,8 @@ static inline int lockdep_match_key(stru + return lock->key == key; + } + ++struct lock_class *lockdep_hlock_class(struct held_lock *hlock); ++ + /* + * Acquire a lock. + * +diff -Nurp linux-5.15.37/include/linux/mm.h linux-5.15.37-aufs/include/linux/mm.h +--- linux-5.15.37/include/linux/mm.h 2022-03-20 22:14:17.000000000 +0200 ++++ linux-5.15.37-aufs/include/linux/mm.h 2022-04-08 20:22:30.618616768 +0300 +@@ -1895,6 +1895,43 @@ static inline void unmap_shared_mapping_ + unmap_mapping_range(mapping, holebegin, holelen, 0); + } + ++#if IS_ENABLED(CONFIG_AUFS_FS) ++extern void vma_do_file_update_time(struct vm_area_struct *, const char[], int); ++extern struct file *vma_do_pr_or_file(struct vm_area_struct *, const char[], ++ int); ++extern void vma_do_get_file(struct vm_area_struct *, const char[], int); ++extern void vma_do_fput(struct vm_area_struct *, const char[], int); ++ ++#define vma_file_update_time(vma) vma_do_file_update_time(vma, __func__, \ ++ __LINE__) ++#define vma_pr_or_file(vma) vma_do_pr_or_file(vma, __func__, \ ++ __LINE__) ++#define vma_get_file(vma) vma_do_get_file(vma, __func__, __LINE__) ++#define vma_fput(vma) vma_do_fput(vma, __func__, __LINE__) ++ ++#ifndef CONFIG_MMU ++extern struct file *vmr_do_pr_or_file(struct vm_region *, const char[], int); ++extern void vmr_do_fput(struct vm_region *, const char[], int); ++ ++#define vmr_pr_or_file(region) vmr_do_pr_or_file(region, __func__, \ ++ __LINE__) ++#define vmr_fput(region) vmr_do_fput(region, __func__, __LINE__) ++#endif /* !CONFIG_MMU */ ++ ++#else ++ ++#define vma_file_update_time(vma) file_update_time((vma)->vm_file) ++#define vma_pr_or_file(vma) (vma)->vm_file ++#define vma_get_file(vma) get_file((vma)->vm_file) ++#define vma_fput(vma) fput((vma)->vm_file) ++ ++#ifndef CONFIG_MMU ++#define vmr_pr_or_file(region) (region)->vm_file ++#define vmr_fput(region) fput((region)->vm_file) ++#endif /* !CONFIG_MMU */ ++ ++#endif /* CONFIG_AUFS_FS */ ++ + extern int access_process_vm(struct task_struct *tsk, unsigned long addr, + void *buf, int len, unsigned int gup_flags); + extern int access_remote_vm(struct mm_struct *mm, unsigned long addr, +diff -Nurp linux-5.15.37/include/linux/mm_types.h linux-5.15.37-aufs/include/linux/mm_types.h +--- linux-5.15.37/include/linux/mm_types.h 2022-03-20 22:14:17.000000000 +0200 ++++ linux-5.15.37-aufs/include/linux/mm_types.h 2022-04-08 20:22:30.618616768 +0300 +@@ -344,6 +344,9 @@ struct vm_region { + unsigned long vm_top; /* region allocated to here */ + unsigned long vm_pgoff; /* the offset in vm_file corresponding to vm_start */ + struct file *vm_file; /* the backing file or NULL */ ++#if IS_ENABLED(CONFIG_AUFS_FS) ++ struct file *vm_prfile; /* the virtual backing file or NULL */ ++#endif + + int vm_usage; /* region usage count (access under nommu_region_sem) */ + bool vm_icache_flushed : 1; /* true if the icache has been flushed for +@@ -440,6 +443,9 @@ struct vm_area_struct { + unsigned long vm_pgoff; /* Offset (within vm_file) in PAGE_SIZE + units */ + struct file * vm_file; /* File we map to (can be NULL). */ ++#if IS_ENABLED(CONFIG_AUFS_FS) ++ struct file *vm_prfile; /* shadow of vm_file */ ++#endif + void * vm_private_data; /* was vm_pte (shared mem) */ + + #ifdef CONFIG_SWAP +diff -Nurp linux-5.15.37/include/linux/mnt_namespace.h linux-5.15.37-aufs/include/linux/mnt_namespace.h +--- linux-5.15.37/include/linux/mnt_namespace.h 2022-03-20 22:14:17.000000000 +0200 ++++ linux-5.15.37-aufs/include/linux/mnt_namespace.h 2022-04-08 20:22:30.618616768 +0300 +@@ -7,12 +7,15 @@ struct mnt_namespace; + struct fs_struct; + struct user_namespace; + struct ns_common; ++struct vfsmount; + + extern struct mnt_namespace *copy_mnt_ns(unsigned long, struct mnt_namespace *, + struct user_namespace *, struct fs_struct *); + extern void put_mnt_ns(struct mnt_namespace *ns); + extern struct ns_common *from_mnt_ns(struct mnt_namespace *); + ++extern int is_current_mnt_ns(struct vfsmount *mnt); ++ + extern const struct file_operations proc_mounts_operations; + extern const struct file_operations proc_mountinfo_operations; + extern const struct file_operations proc_mountstats_operations; +diff -Nurp linux-5.15.37/include/linux/splice.h linux-5.15.37-aufs/include/linux/splice.h +--- linux-5.15.37/include/linux/splice.h 2022-03-20 22:14:17.000000000 +0200 ++++ linux-5.15.37-aufs/include/linux/splice.h 2022-04-08 20:22:30.618616768 +0300 +@@ -93,4 +93,10 @@ extern void splice_shrink_spd(struct spl + + extern const struct pipe_buf_operations page_cache_pipe_buf_ops; + extern const struct pipe_buf_operations default_pipe_buf_ops; ++ ++extern long do_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags); ++extern long do_splice_to(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags); + #endif +diff -Nurp linux-5.15.37/include/uapi/linux/aufs_type.h linux-5.15.37-aufs/include/uapi/linux/aufs_type.h +--- linux-5.15.37/include/uapi/linux/aufs_type.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/include/uapi/linux/aufs_type.h 2022-04-08 20:22:30.618616768 +0300 +@@ -0,0 +1,439 @@ ++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ ++/* ++ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ */ ++ ++#ifndef __AUFS_TYPE_H__ ++#define __AUFS_TYPE_H__ ++ ++#define AUFS_NAME "aufs" ++ ++#ifdef __KERNEL__ ++/* ++ * define it before including all other headers. ++ * sched.h may use pr_* macros before defining "current", so define the ++ * no-current version first, and re-define later. ++ */ ++#define pr_fmt(fmt) AUFS_NAME " %s:%d: " fmt, __func__, __LINE__ ++#include ++#undef pr_fmt ++#define pr_fmt(fmt) \ ++ AUFS_NAME " %s:%d:%.*s[%d]: " fmt, __func__, __LINE__, \ ++ (int)sizeof(current->comm), current->comm, current->pid ++#include ++#else ++#include ++#include ++#include ++#endif /* __KERNEL__ */ ++ ++#define AUFS_VERSION "5.17" ++ ++/* todo? move this to linux-2.6.19/include/magic.h */ ++#define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's') ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef __KERNEL__ ++#ifdef CONFIG_AUFS_BRANCH_MAX_127 ++typedef int8_t aufs_bindex_t; ++#define AUFS_BRANCH_MAX 127 ++#else ++typedef int16_t aufs_bindex_t; ++#ifdef CONFIG_AUFS_BRANCH_MAX_511 ++#define AUFS_BRANCH_MAX 511 ++#elif defined(CONFIG_AUFS_BRANCH_MAX_1023) ++#define AUFS_BRANCH_MAX 1023 ++#elif defined(CONFIG_AUFS_BRANCH_MAX_32767) ++#define AUFS_BRANCH_MAX 32767 ++#endif ++#endif ++ ++#ifndef AUFS_BRANCH_MAX ++#error unknown CONFIG_AUFS_BRANCH_MAX value ++#endif ++#endif /* __KERNEL__ */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define AUFS_FSTYPE AUFS_NAME ++ ++#define AUFS_ROOT_INO 2 ++#define AUFS_FIRST_INO 11 ++ ++#define AUFS_WH_PFX ".wh." ++#define AUFS_WH_PFX_LEN ((int)sizeof(AUFS_WH_PFX) - 1) ++#define AUFS_WH_TMP_LEN 4 ++/* a limit for rmdir/rename a dir and copyup */ ++#define AUFS_MAX_NAMELEN (NAME_MAX \ ++ - AUFS_WH_PFX_LEN * 2 /* doubly whiteouted */\ ++ - 1 /* dot */\ ++ - AUFS_WH_TMP_LEN) /* hex */ ++#define AUFS_XINO_FNAME "." AUFS_NAME ".xino" ++#define AUFS_XINO_DEFPATH "/tmp/" AUFS_XINO_FNAME ++#define AUFS_XINO_DEF_SEC 30 /* seconds */ ++#define AUFS_XINO_DEF_TRUNC 45 /* percentage */ ++#define AUFS_DIRWH_DEF 3 ++#define AUFS_RDCACHE_DEF 10 /* seconds */ ++#define AUFS_RDCACHE_MAX 3600 /* seconds */ ++#define AUFS_RDBLK_DEF 512 /* bytes */ ++#define AUFS_RDHASH_DEF 32 ++#define AUFS_WKQ_NAME AUFS_NAME "d" ++#define AUFS_MFS_DEF_SEC 30 /* seconds */ ++#define AUFS_MFS_MAX_SEC 3600 /* seconds */ ++#define AUFS_FHSM_CACHE_DEF_SEC 30 /* seconds */ ++#define AUFS_PLINK_WARN 50 /* number of plinks in a single bucket */ ++ ++/* pseudo-link maintenace under /proc */ ++#define AUFS_PLINK_MAINT_NAME "plink_maint" ++#define AUFS_PLINK_MAINT_DIR "fs/" AUFS_NAME ++#define AUFS_PLINK_MAINT_PATH AUFS_PLINK_MAINT_DIR "/" AUFS_PLINK_MAINT_NAME ++ ++/* dirren, renamed dir */ ++#define AUFS_DR_INFO_PFX AUFS_WH_PFX ".dr." ++#define AUFS_DR_BRHINO_NAME AUFS_WH_PFX "hino" ++/* whiteouted doubly */ ++#define AUFS_WH_DR_INFO_PFX AUFS_WH_PFX AUFS_DR_INFO_PFX ++#define AUFS_WH_DR_BRHINO AUFS_WH_PFX AUFS_DR_BRHINO_NAME ++ ++#define AUFS_DIROPQ_NAME AUFS_WH_PFX ".opq" /* whiteouted doubly */ ++#define AUFS_WH_DIROPQ AUFS_WH_PFX AUFS_DIROPQ_NAME ++ ++#define AUFS_BASE_NAME AUFS_WH_PFX AUFS_NAME ++#define AUFS_PLINKDIR_NAME AUFS_WH_PFX "plnk" ++#define AUFS_ORPHDIR_NAME AUFS_WH_PFX "orph" ++ ++/* doubly whiteouted */ ++#define AUFS_WH_BASE AUFS_WH_PFX AUFS_BASE_NAME ++#define AUFS_WH_PLINKDIR AUFS_WH_PFX AUFS_PLINKDIR_NAME ++#define AUFS_WH_ORPHDIR AUFS_WH_PFX AUFS_ORPHDIR_NAME ++ ++/* branch permissions and attributes */ ++#define AUFS_BRPERM_RW "rw" ++#define AUFS_BRPERM_RO "ro" ++#define AUFS_BRPERM_RR "rr" ++#define AUFS_BRATTR_COO_REG "coo_reg" ++#define AUFS_BRATTR_COO_ALL "coo_all" ++#define AUFS_BRATTR_FHSM "fhsm" ++#define AUFS_BRATTR_UNPIN "unpin" ++#define AUFS_BRATTR_ICEX "icex" ++#define AUFS_BRATTR_ICEX_SEC "icexsec" ++#define AUFS_BRATTR_ICEX_SYS "icexsys" ++#define AUFS_BRATTR_ICEX_TR "icextr" ++#define AUFS_BRATTR_ICEX_USR "icexusr" ++#define AUFS_BRATTR_ICEX_OTH "icexoth" ++#define AUFS_BRRATTR_WH "wh" ++#define AUFS_BRWATTR_NLWH "nolwh" ++#define AUFS_BRWATTR_MOO "moo" ++ ++#define AuBrPerm_RW 1 /* writable, hardlinkable wh */ ++#define AuBrPerm_RO (1 << 1) /* readonly */ ++#define AuBrPerm_RR (1 << 2) /* natively readonly */ ++#define AuBrPerm_Mask (AuBrPerm_RW | AuBrPerm_RO | AuBrPerm_RR) ++ ++#define AuBrAttr_COO_REG (1 << 3) /* copy-up on open */ ++#define AuBrAttr_COO_ALL (1 << 4) ++#define AuBrAttr_COO_Mask (AuBrAttr_COO_REG | AuBrAttr_COO_ALL) ++ ++#define AuBrAttr_FHSM (1 << 5) /* file-based hsm */ ++#define AuBrAttr_UNPIN (1 << 6) /* rename-able top dir of ++ branch. meaningless since ++ linux-3.18-rc1 */ ++ ++/* ignore error in copying XATTR */ ++#define AuBrAttr_ICEX_SEC (1 << 7) ++#define AuBrAttr_ICEX_SYS (1 << 8) ++#define AuBrAttr_ICEX_TR (1 << 9) ++#define AuBrAttr_ICEX_USR (1 << 10) ++#define AuBrAttr_ICEX_OTH (1 << 11) ++#define AuBrAttr_ICEX (AuBrAttr_ICEX_SEC \ ++ | AuBrAttr_ICEX_SYS \ ++ | AuBrAttr_ICEX_TR \ ++ | AuBrAttr_ICEX_USR \ ++ | AuBrAttr_ICEX_OTH) ++ ++#define AuBrRAttr_WH (1 << 12) /* whiteout-able */ ++#define AuBrRAttr_Mask AuBrRAttr_WH ++ ++#define AuBrWAttr_NoLinkWH (1 << 13) /* un-hardlinkable whiteouts */ ++#define AuBrWAttr_MOO (1 << 14) /* move-up on open */ ++#define AuBrWAttr_Mask (AuBrWAttr_NoLinkWH | AuBrWAttr_MOO) ++ ++#define AuBrAttr_CMOO_Mask (AuBrAttr_COO_Mask | AuBrWAttr_MOO) ++ ++/* #warning test userspace */ ++#ifdef __KERNEL__ ++#ifndef CONFIG_AUFS_FHSM ++#undef AuBrAttr_FHSM ++#define AuBrAttr_FHSM 0 ++#endif ++#ifndef CONFIG_AUFS_XATTR ++#undef AuBrAttr_ICEX ++#define AuBrAttr_ICEX 0 ++#undef AuBrAttr_ICEX_SEC ++#define AuBrAttr_ICEX_SEC 0 ++#undef AuBrAttr_ICEX_SYS ++#define AuBrAttr_ICEX_SYS 0 ++#undef AuBrAttr_ICEX_TR ++#define AuBrAttr_ICEX_TR 0 ++#undef AuBrAttr_ICEX_USR ++#define AuBrAttr_ICEX_USR 0 ++#undef AuBrAttr_ICEX_OTH ++#define AuBrAttr_ICEX_OTH 0 ++#endif ++#endif ++ ++/* the longest combination */ ++/* AUFS_BRATTR_ICEX and AUFS_BRATTR_ICEX_TR don't affect here */ ++#define AuBrPermStrSz sizeof(AUFS_BRPERM_RW \ ++ "+" AUFS_BRATTR_COO_REG \ ++ "+" AUFS_BRATTR_FHSM \ ++ "+" AUFS_BRATTR_UNPIN \ ++ "+" AUFS_BRATTR_ICEX_SEC \ ++ "+" AUFS_BRATTR_ICEX_SYS \ ++ "+" AUFS_BRATTR_ICEX_USR \ ++ "+" AUFS_BRATTR_ICEX_OTH \ ++ "+" AUFS_BRWATTR_NLWH) ++ ++typedef struct { ++ char a[AuBrPermStrSz]; ++} au_br_perm_str_t; ++ ++static inline int au_br_writable(int brperm) ++{ ++ return brperm & AuBrPerm_RW; ++} ++ ++static inline int au_br_whable(int brperm) ++{ ++ return brperm & (AuBrPerm_RW | AuBrRAttr_WH); ++} ++ ++static inline int au_br_wh_linkable(int brperm) ++{ ++ return !(brperm & AuBrWAttr_NoLinkWH); ++} ++ ++static inline int au_br_cmoo(int brperm) ++{ ++ return brperm & AuBrAttr_CMOO_Mask; ++} ++ ++static inline int au_br_fhsm(int brperm) ++{ ++ return brperm & AuBrAttr_FHSM; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ioctl */ ++enum { ++ /* readdir in userspace */ ++ AuCtl_RDU, ++ AuCtl_RDU_INO, ++ ++ AuCtl_WBR_FD, /* pathconf wrapper */ ++ AuCtl_IBUSY, /* busy inode */ ++ AuCtl_MVDOWN, /* move-down */ ++ AuCtl_BR, /* info about branches */ ++ AuCtl_FHSM_FD /* connection for fhsm */ ++}; ++ ++/* borrowed from linux/include/linux/kernel.h */ ++#ifndef ALIGN ++#ifdef _GNU_SOURCE ++#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1) ++#else ++#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) ++#endif ++#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask)) ++#endif ++ ++/* borrowed from linux/include/linux/compiler-gcc3.h */ ++#ifndef __aligned ++#define __aligned(x) __attribute__((aligned(x))) ++#endif ++ ++#ifdef __KERNEL__ ++#ifndef __packed ++#define __packed __attribute__((packed)) ++#endif ++#endif ++ ++struct au_rdu_cookie { ++ uint64_t h_pos; ++ int16_t bindex; ++ uint8_t flags; ++ uint8_t pad; ++ uint32_t generation; ++} __aligned(8); ++ ++struct au_rdu_ent { ++ uint64_t ino; ++ int16_t bindex; ++ uint8_t type; ++ uint8_t nlen; ++ uint8_t wh; ++ char name[]; ++} __aligned(8); ++ ++static inline int au_rdu_len(int nlen) ++{ ++ /* include the terminating NULL */ ++ return ALIGN(sizeof(struct au_rdu_ent) + nlen + 1, ++ sizeof(uint64_t)); ++} ++ ++union au_rdu_ent_ul { ++ struct au_rdu_ent __user *e; ++ uint64_t ul; ++}; ++ ++enum { ++ AufsCtlRduV_SZ, ++ AufsCtlRduV_End ++}; ++ ++struct aufs_rdu { ++ /* input */ ++ union { ++ uint64_t sz; /* AuCtl_RDU */ ++ uint64_t nent; /* AuCtl_RDU_INO */ ++ }; ++ union au_rdu_ent_ul ent; ++ uint16_t verify[AufsCtlRduV_End]; ++ ++ /* input/output */ ++ uint32_t blk; ++ ++ /* output */ ++ union au_rdu_ent_ul tail; ++ /* number of entries which were added in a single call */ ++ uint64_t rent; ++ uint8_t full; ++ uint8_t shwh; ++ ++ struct au_rdu_cookie cookie; ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dirren. the branch is identified by the filename who contains this */ ++struct au_drinfo { ++ uint64_t ino; ++ union { ++ uint8_t oldnamelen; ++ uint64_t _padding; ++ }; ++ uint8_t oldname[]; ++} __aligned(8); ++ ++struct au_drinfo_fdata { ++ uint32_t magic; ++ struct au_drinfo drinfo; ++} __aligned(8); ++ ++#define AUFS_DRINFO_MAGIC_V1 ('a' << 24 | 'd' << 16 | 'r' << 8 | 0x01) ++/* future */ ++#define AUFS_DRINFO_MAGIC_V2 ('a' << 24 | 'd' << 16 | 'r' << 8 | 0x02) ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct aufs_wbr_fd { ++ uint32_t oflags; ++ int16_t brid; ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct aufs_ibusy { ++ uint64_t ino, h_ino; ++ int16_t bindex; ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* error code for move-down */ ++/* the actual message strings are implemented in aufs-util.git */ ++enum { ++ EAU_MVDOWN_OPAQUE = 1, ++ EAU_MVDOWN_WHITEOUT, ++ EAU_MVDOWN_UPPER, ++ EAU_MVDOWN_BOTTOM, ++ EAU_MVDOWN_NOUPPER, ++ EAU_MVDOWN_NOLOWERBR, ++ EAU_Last ++}; ++ ++/* flags for move-down */ ++#define AUFS_MVDOWN_DMSG 1 ++#define AUFS_MVDOWN_OWLOWER (1 << 1) /* overwrite lower */ ++#define AUFS_MVDOWN_KUPPER (1 << 2) /* keep upper */ ++#define AUFS_MVDOWN_ROLOWER (1 << 3) /* do even if lower is RO */ ++#define AUFS_MVDOWN_ROLOWER_R (1 << 4) /* did on lower RO */ ++#define AUFS_MVDOWN_ROUPPER (1 << 5) /* do even if upper is RO */ ++#define AUFS_MVDOWN_ROUPPER_R (1 << 6) /* did on upper RO */ ++#define AUFS_MVDOWN_BRID_UPPER (1 << 7) /* upper brid */ ++#define AUFS_MVDOWN_BRID_LOWER (1 << 8) /* lower brid */ ++#define AUFS_MVDOWN_FHSM_LOWER (1 << 9) /* find fhsm attr for lower */ ++#define AUFS_MVDOWN_STFS (1 << 10) /* req. stfs */ ++#define AUFS_MVDOWN_STFS_FAILED (1 << 11) /* output: stfs is unusable */ ++#define AUFS_MVDOWN_BOTTOM (1 << 12) /* output: no more lowers */ ++ ++/* index for move-down */ ++enum { ++ AUFS_MVDOWN_UPPER, ++ AUFS_MVDOWN_LOWER, ++ AUFS_MVDOWN_NARRAY ++}; ++ ++/* ++ * additional info of move-down ++ * number of free blocks and inodes. ++ * subset of struct kstatfs, but smaller and always 64bit. ++ */ ++struct aufs_stfs { ++ uint64_t f_blocks; ++ uint64_t f_bavail; ++ uint64_t f_files; ++ uint64_t f_ffree; ++}; ++ ++struct aufs_stbr { ++ int16_t brid; /* optional input */ ++ int16_t bindex; /* output */ ++ struct aufs_stfs stfs; /* output when AUFS_MVDOWN_STFS set */ ++} __aligned(8); ++ ++struct aufs_mvdown { ++ uint32_t flags; /* input/output */ ++ struct aufs_stbr stbr[AUFS_MVDOWN_NARRAY]; /* input/output */ ++ int8_t au_errno; /* output */ ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++union aufs_brinfo { ++ /* PATH_MAX may differ between kernel-space and user-space */ ++ char _spacer[4096]; ++ struct { ++ int16_t id; ++ int perm; ++ char path[]; ++ }; ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define AuCtlType 'A' ++#define AUFS_CTL_RDU _IOWR(AuCtlType, AuCtl_RDU, struct aufs_rdu) ++#define AUFS_CTL_RDU_INO _IOWR(AuCtlType, AuCtl_RDU_INO, struct aufs_rdu) ++#define AUFS_CTL_WBR_FD _IOW(AuCtlType, AuCtl_WBR_FD, \ ++ struct aufs_wbr_fd) ++#define AUFS_CTL_IBUSY _IOWR(AuCtlType, AuCtl_IBUSY, struct aufs_ibusy) ++#define AUFS_CTL_MVDOWN _IOWR(AuCtlType, AuCtl_MVDOWN, \ ++ struct aufs_mvdown) ++#define AUFS_CTL_BRINFO _IOW(AuCtlType, AuCtl_BR, union aufs_brinfo) ++#define AUFS_CTL_FHSM_FD _IOW(AuCtlType, AuCtl_FHSM_FD, int) ++ ++#endif /* __AUFS_TYPE_H__ */ +diff -Nurp linux-5.15.37/kernel/fork.c linux-5.15.37-aufs/kernel/fork.c +--- linux-5.15.37/kernel/fork.c 2022-03-20 22:14:17.000000000 +0200 ++++ linux-5.15.37-aufs/kernel/fork.c 2022-04-08 20:22:30.618616768 +0300 +@@ -575,7 +575,7 @@ static __latent_entropy int dup_mmap(str + if (file) { + struct address_space *mapping = file->f_mapping; + +- get_file(file); ++ vma_get_file(tmp); + i_mmap_lock_write(mapping); + if (tmp->vm_flags & VM_SHARED) + mapping_allow_writable(mapping); +diff -Nurp linux-5.15.37/kernel/locking/lockdep.c linux-5.15.37-aufs/kernel/locking/lockdep.c +--- linux-5.15.37/kernel/locking/lockdep.c 2022-04-08 20:07:30.703499501 +0300 ++++ linux-5.15.37-aufs/kernel/locking/lockdep.c 2022-04-08 20:22:30.619616817 +0300 +@@ -187,7 +187,7 @@ unsigned long max_lock_class_idx; + struct lock_class lock_classes[MAX_LOCKDEP_KEYS]; + DECLARE_BITMAP(lock_classes_in_use, MAX_LOCKDEP_KEYS); + +-static inline struct lock_class *hlock_class(struct held_lock *hlock) ++inline struct lock_class *lockdep_hlock_class(struct held_lock *hlock) + { + unsigned int class_idx = hlock->class_idx; + +@@ -208,6 +208,7 @@ static inline struct lock_class *hlock_c + */ + return lock_classes + class_idx; + } ++#define hlock_class(hlock) lockdep_hlock_class(hlock) + + #ifdef CONFIG_LOCK_STAT + static DEFINE_PER_CPU(struct lock_class_stats[MAX_LOCKDEP_KEYS], cpu_lock_stats); +diff -Nurp linux-5.15.37/MAINTAINERS linux-5.15.37-aufs/MAINTAINERS +--- linux-5.15.37/MAINTAINERS 2022-04-08 20:07:30.611494969 +0300 ++++ linux-5.15.37-aufs/MAINTAINERS 2022-04-08 20:22:30.610616377 +0300 +@@ -3235,6 +3235,19 @@ F: include/uapi/linux/audit.h + F: kernel/audit* + F: lib/*audit.c + ++AUFS (advanced multi layered unification filesystem) FILESYSTEM ++M: "J. R. Okajima" ++L: aufs-users@lists.sourceforge.net (members only) ++L: linux-unionfs@vger.kernel.org ++S: Supported ++W: http://aufs.sourceforge.net ++T: git://github.com/sfjro/aufs4-linux.git ++F: Documentation/ABI/testing/debugfs-aufs ++F: Documentation/ABI/testing/sysfs-aufs ++F: Documentation/filesystems/aufs/ ++F: fs/aufs/ ++F: include/uapi/linux/aufs_type.h ++ + AUXILIARY DISPLAY DRIVERS + M: Miguel Ojeda + S: Maintained +diff -Nurp linux-5.15.37/mm/filemap.c linux-5.15.37-aufs/mm/filemap.c +--- linux-5.15.37/mm/filemap.c 2022-03-20 22:14:17.000000000 +0200 ++++ linux-5.15.37-aufs/mm/filemap.c 2022-04-08 20:22:30.619616817 +0300 +@@ -3350,7 +3350,7 @@ vm_fault_t filemap_page_mkwrite(struct vm_fault *vmf) + vm_fault_t ret = VM_FAULT_LOCKED; + + sb_start_pagefault(mapping->host->i_sb); +- file_update_time(vmf->vma->vm_file); ++ vma_file_update_time(vmf->vma); + lock_page(page); + if (page->mapping != mapping) { + unlock_page(page); +diff -Nurp linux-5.15.37/mm/Makefile linux-5.15.37-aufs/mm/Makefile +--- linux-5.15.37/mm/Makefile 2022-03-20 22:14:17.000000000 +0200 ++++ linux-5.15.37-aufs/mm/Makefile 2022-04-08 20:22:30.619616817 +0300 +@@ -132,3 +132,4 @@ obj-$(CONFIG_PAGE_REPORTING) += page_rep + obj-$(CONFIG_IO_MAPPING) += io-mapping.o + obj-$(CONFIG_HAVE_BOOTMEM_INFO_NODE) += bootmem_info.o + obj-$(CONFIG_GENERIC_IOREMAP) += ioremap.o ++obj-$(CONFIG_AUFS_FS:m=y) += prfile.o +diff -Nurp linux-5.15.37/mm/mmap.c linux-5.15.37-aufs/mm/mmap.c +--- linux-5.15.37/mm/mmap.c 2022-04-08 20:07:30.709499796 +0300 ++++ linux-5.15.37-aufs/mm/mmap.c 2022-04-08 20:22:30.619616817 +0300 +@@ -184,7 +184,7 @@ static struct vm_area_struct *remove_vma + if (vma->vm_ops && vma->vm_ops->close) + vma->vm_ops->close(vma); + if (vma->vm_file) +- fput(vma->vm_file); ++ vma_fput(vma); + mpol_put(vma_policy(vma)); + vm_area_free(vma); + return next; +@@ -953,7 +953,7 @@ again: + if (remove_next) { + if (file) { + uprobe_munmap(next, next->vm_start, next->vm_end); +- fput(file); ++ vma_fput(vma); + } + if (next->anon_vma) + anon_vma_merge(vma, next); +@@ -1879,7 +1879,7 @@ out: + return addr; + + unmap_and_free_vma: +- fput(vma->vm_file); ++ vma_fput(vma); + vma->vm_file = NULL; + + /* Undo any partial mapping done by a device driver. */ +@@ -2737,7 +2737,7 @@ int __split_vma(struct mm_struct *mm, st + goto out_free_mpol; + + if (new->vm_file) +- get_file(new->vm_file); ++ vma_get_file(new); + + if (new->vm_ops && new->vm_ops->open) + new->vm_ops->open(new); +@@ -2756,7 +2756,7 @@ int __split_vma(struct mm_struct *mm, st + if (new->vm_ops && new->vm_ops->close) + new->vm_ops->close(new); + if (new->vm_file) +- fput(new->vm_file); ++ vma_fput(new); + unlink_anon_vmas(new); + out_free_mpol: + mpol_put(vma_policy(new)); +@@ -2951,6 +2951,9 @@ SYSCALL_DEFINE5(remap_file_pages, unsign + unsigned long populate = 0; + unsigned long ret = -EINVAL; + struct file *file; ++#if IS_ENABLED(CONFIG_AUFS_FS) ++ struct file *prfile; ++#endif + + pr_warn_once("%s (%d) uses deprecated remap_file_pages() syscall. See Documentation/vm/remap_file_pages.rst.\n", + current->comm, current->pid); +@@ -3006,10 +3009,34 @@ SYSCALL_DEFINE5(remap_file_pages, unsign + if (vma->vm_flags & VM_LOCKED) + flags |= MAP_LOCKED; + ++#if IS_ENABLED(CONFIG_AUFS_FS) ++ vma_get_file(vma); ++ file = vma->vm_file; ++ prfile = vma->vm_prfile; ++ ret = do_mmap(vma->vm_file, start, size, ++ prot, flags, pgoff, &populate, NULL); ++ if (!IS_ERR_VALUE(ret) && file && prfile) { ++ struct vm_area_struct *new_vma; ++ ++ new_vma = find_vma(mm, ret); ++ if (!new_vma->vm_prfile) ++ new_vma->vm_prfile = prfile; ++ if (new_vma != vma) ++ get_file(prfile); ++ } ++ /* ++ * two fput()s instead of vma_fput(vma), ++ * coz vma may not be available anymore. ++ */ ++ fput(file); ++ if (prfile) ++ fput(prfile); ++#else + file = get_file(vma->vm_file); + ret = do_mmap(vma->vm_file, start, size, + prot, flags, pgoff, &populate, NULL); + fput(file); ++#endif /* CONFIG_AUFS_FS */ + out: + mmap_write_unlock(mm); + if (populate) +@@ -3291,7 +3318,7 @@ struct vm_area_struct *copy_vma(struct v + if (anon_vma_clone(new_vma, vma)) + goto out_free_mempol; + if (new_vma->vm_file) +- get_file(new_vma->vm_file); ++ vma_get_file(new_vma); + if (new_vma->vm_ops && new_vma->vm_ops->open) + new_vma->vm_ops->open(new_vma); + vma_link(mm, new_vma, prev, rb_link, rb_parent); +diff -Nurp linux-5.15.37/mm/nommu.c linux-5.15.37-aufs/mm/nommu.c +--- linux-5.15.37/mm/nommu.c 2022-03-20 22:14:17.000000000 +0200 ++++ linux-5.15.37-aufs/mm/nommu.c 2022-04-08 20:22:30.619616817 +0300 +@@ -522,7 +522,7 @@ static void __put_nommu_region(struct vm + up_write(&nommu_region_sem); + + if (region->vm_file) +- fput(region->vm_file); ++ vmr_fput(region); + + /* IO memory and memory shared directly out of the pagecache + * from ramfs/tmpfs mustn't be released here */ +@@ -654,7 +654,7 @@ static void delete_vma(struct mm_struct + if (vma->vm_ops && vma->vm_ops->close) + vma->vm_ops->close(vma); + if (vma->vm_file) +- fput(vma->vm_file); ++ vma_fput(vma); + put_nommu_region(vma->vm_region); + vm_area_free(vma); + } +@@ -1174,7 +1174,7 @@ unsigned long do_mmap(struct file *file, + goto error_just_free; + } + } +- fput(region->vm_file); ++ vmr_fput(region); + kmem_cache_free(vm_region_jar, region); + region = pregion; + result = start; +@@ -1251,10 +1251,10 @@ error_just_free: + up_write(&nommu_region_sem); + error: + if (region->vm_file) +- fput(region->vm_file); ++ vmr_fput(region); + kmem_cache_free(vm_region_jar, region); + if (vma->vm_file) +- fput(vma->vm_file); ++ vma_fput(vma); + vm_area_free(vma); + return ret; + +diff -Nurp linux-5.15.37/mm/prfile.c linux-5.15.37-aufs/mm/prfile.c +--- linux-5.15.37/mm/prfile.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.37-aufs/mm/prfile.c 2022-04-08 20:22:30.619616817 +0300 +@@ -0,0 +1,86 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Mainly for aufs which mmap(2) different file and wants to print different ++ * path in /proc/PID/maps. ++ * Call these functions via macros defined in linux/mm.h. ++ * ++ * See Documentation/filesystems/aufs/design/06mmap.txt ++ * ++ * Copyright (c) 2014-2021 Junjro R. Okajima ++ * Copyright (c) 2014 Ian Campbell ++ */ ++ ++#include ++#include ++#include ++ ++/* #define PRFILE_TRACE */ ++static inline void prfile_trace(struct file *f, struct file *pr, ++ const char func[], int line, const char func2[]) ++{ ++#ifdef PRFILE_TRACE ++ if (pr) ++ pr_info("%s:%d: %s, %pD2\n", func, line, func2, f); ++#endif ++} ++ ++void vma_do_file_update_time(struct vm_area_struct *vma, const char func[], ++ int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ file_update_time(f); ++ if (f && pr) ++ file_update_time(pr); ++} ++ ++struct file *vma_do_pr_or_file(struct vm_area_struct *vma, const char func[], ++ int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ return (f && pr) ? pr : f; ++} ++ ++void vma_do_get_file(struct vm_area_struct *vma, const char func[], int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ get_file(f); ++ if (f && pr) ++ get_file(pr); ++} ++ ++void vma_do_fput(struct vm_area_struct *vma, const char func[], int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ fput(f); ++ if (f && pr) ++ fput(pr); ++} ++ ++#ifndef CONFIG_MMU ++struct file *vmr_do_pr_or_file(struct vm_region *region, const char func[], ++ int line) ++{ ++ struct file *f = region->vm_file, *pr = region->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ return (f && pr) ? pr : f; ++} ++ ++void vmr_do_fput(struct vm_region *region, const char func[], int line) ++{ ++ struct file *f = region->vm_file, *pr = region->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ fput(f); ++ if (f && pr) ++ fput(pr); ++} ++#endif /* !CONFIG_MMU */ diff --git a/kernel/tools/perf/files/patches/mageia/fs-procfs-do-not-list-TID-0-in-proc-pid-task.patch b/kernel/tools/perf/files/patches/mageia/fs-procfs-do-not-list-TID-0-in-proc-pid-task.patch new file mode 100644 index 0000000000..c366d5b71a --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/fs-procfs-do-not-list-TID-0-in-proc-pid-task.patch @@ -0,0 +1,36 @@ +From 435664ed44c4a17e6715d007061e2b155d3535c8 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Fri, 1 Oct 2021 13:38:15 +1000 +Subject: procfs: do not list TID 0 in /proc//task + +If a task exits concurrently, task_pid_nr_ns may return 0. + +Link: https://lkml.kernel.org/r/8735pn5dx7.fsf@oldenburg.str.redhat.com +Signed-off-by: Florian Weimer +Acked-by: Christian Brauner +Cc: Kees Cook +Cc: "Eric W. Biederman" +Cc: Alexey Dobriyan +Signed-off-by: Andrew Morton +Signed-off-by: Stephen Rothwell +--- + fs/proc/base.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/fs/proc/base.c b/fs/proc/base.c +index 533d5836eb9a4..54f29399088f0 100644 +--- a/fs/proc/base.c ++++ b/fs/proc/base.c +@@ -3800,6 +3800,9 @@ static int proc_task_readdir(struct file *file, struct dir_context *ctx) + char name[10 + 1]; + unsigned int len; + tid = task_pid_nr_ns(task, ns); ++ if (!tid) ++ /* The task has just exited. */ ++ continue; + len = snprintf(name, sizeof(name), "%u", tid); + if (!proc_fill_cache(file, ctx, name, len, + proc_task_instantiate, task, NULL)) { +-- +cgit 1.2.3-1.el7 + diff --git a/kernel/tools/perf/files/patches/mageia/platform-x86-add-shuttle-wmi-driver.patch b/kernel/tools/perf/files/patches/mageia/platform-x86-add-shuttle-wmi-driver.patch new file mode 100644 index 0000000000..dfe13ed441 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/platform-x86-add-shuttle-wmi-driver.patch @@ -0,0 +1,1439 @@ + + Documentation/ABI/testing/sysfs-platform-shuttle-wmi | 72 +++++++++ + MAINTAINERS | 6 + drivers/platform/x86/Kconfig | 15 ++ + drivers/platform/x86/Makefile | 3 + drivers/platform/x86/shuttle-wmi.c | 1297 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 5 files changed, 1393 insertions(+) + +diff -Nurp linux-5.15.1/Documentation/ABI/testing/sysfs-platform-shuttle-wmi linux-5.15.1-shuttle/Documentation/ABI/testing/sysfs-platform-shuttle-wmi +--- linux-5.15.1/Documentation/ABI/testing/sysfs-platform-shuttle-wmi 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.1-shuttle/Documentation/ABI/testing/sysfs-platform-shuttle-wmi 2021-11-08 23:24:45.468092228 +0200 +@@ -0,0 +1,72 @@ ++What: /sys/devices/platform/shuttle_wmi/lcd_auto_adjust ++Date: December 2010 ++KernelVersion: 2.6.36 ++Contact: "Herton Ronaldo Krzesinski" ++Description: ++ This is a write only option (accepts any single value, eg. ++ "echo 1 > lcd_auto_adjust") that starts LCD auto-adjust ++ function, if the machine has this function enabled. Some ++ shuttle machines have LCD attached to analog VGA connector, ++ so uses/needs auto-adjust. ++ ++What: /sys/devices/platform/shuttle_wmi/model_name ++Date: December 2010 ++KernelVersion: 2.6.36 ++Contact: "Herton Ronaldo Krzesinski" ++Description: ++ This is a read only attribute which outputs a string with model ++ name of the machine. When shuttle-wmi can't determine which ++ model it is, "Unknown" is returned. Otherwise, the possible ++ models are "Shuttle MA", "Shuttle DA18IE", "Shuttle DA18IM", ++ "Shuttle X50 V2", "Positivo A14IE01", "Positivo P13", ++ "Positivo P14". ++ ++What: /sys/devices/platform/shuttle_wmi/panel_set_default ++Date: December 2010 ++KernelVersion: 2.6.36 ++Contact: "Herton Ronaldo Krzesinski" ++Description: ++ This is a write only option (accepts any single value, eg. ++ "echo 1 > panel_set_default"). Probably resets panel/lcd to ++ default configuration, function not explained in shuttle wmi ++ documentation. It also starts an auto adjust and color adjust ++ cycle. The function should only work in shuttle machines with ++ LCD attached to an analog VGA connector. ++ ++What: /sys/devices/platform/shuttle_wmi/powersave ++Date: December 2010 ++KernelVersion: 2.6.36 ++Contact: "Herton Ronaldo Krzesinski" ++Description: ++ Control powersave state. 1 means on, 0 means off. ++ When enabled, it basically forces the cpu to stay on powersave ++ state (only works if cpu has P-states support, it is similar to ++ powersave governor in cpufreq) when machine is only running on ++ battery. If not running on battery, this function isn't expected ++ to work, any attempt to enable this returns -EIO. ++ ++What: /sys/devices/platform/shuttle_wmi/touchpad_off ++Date: December 2010 ++KernelVersion: 2.6.36 ++Contact: "Herton Ronaldo Krzesinski" ++Description: ++ Control touchpad state. 1 means off, 0 means on. ++ ++What: /sys/devices/platform/shuttle_wmi/webcam ++Date: December 2010 ++KernelVersion: 2.6.36 ++Contact: "Herton Ronaldo Krzesinski" ++Description: ++ Control webcam state. 1 means on, 0 means off. ++ ++What: /sys/devices/platform/shuttle_wmi/white_balance ++Date: December 2010 ++KernelVersion: 2.6.36 ++Contact: "Herton Ronaldo Krzesinski" ++Description: ++ This is a write only option (accepts any single value, eg. ++ "echo 1 > white_balance"). Probably triggers an automatic ++ white balance adjustment for lcd, function not explained in ++ shuttle wmi documentation. It also starts an auto adjust and ++ color adjust cycle. The function should only work in shuttle ++ machines with LCD attached to an analog VGA connector. +diff -Nurp linux-5.15.1/drivers/platform/x86/Kconfig linux-5.15.1-shuttle/drivers/platform/x86/Kconfig +--- linux-5.15.1/drivers/platform/x86/Kconfig 2021-10-31 22:53:10.000000000 +0200 ++++ linux-5.15.1-shuttle/drivers/platform/x86/Kconfig 2021-11-08 23:24:45.469092275 +0200 +@@ -879,6 +879,21 @@ config PANASONIC_LAPTOP + If you have a Panasonic Let's note laptop (such as the R1(N variant), + R2, R3, R5, T2, W2 and Y2 series), say Y. + ++config SHUTTLE_WMI ++ tristate "Shuttle WMI Extras Driver" ++ depends on ACPI_WMI ++ depends on BACKLIGHT_CLASS_DEVICE ++ depends on RFKILL ++ depends on INPUT ++ select INPUT_SPARSEKMAP ++ help ++ This is a driver for the WMI interface present on some Shuttle ++ machines. It adds controls for wireless, bluetooth and 3g radios, ++ webcam switch, backlight controls, among others. ++ ++ If you have a Shuttle machine with ACPI-WMI interface say Y or M ++ here. ++ + config SONY_LAPTOP + tristate "Sony Laptop Extras" + depends on ACPI +diff -Nurp linux-5.15.1/drivers/platform/x86/Makefile linux-5.15.1-shuttle/drivers/platform/x86/Makefile +--- linux-5.15.1/drivers/platform/x86/Makefile 2021-10-31 22:53:10.000000000 +0200 ++++ linux-5.15.1-shuttle/drivers/platform/x86/Makefile 2021-11-08 23:24:45.469092275 +0200 +@@ -84,6 +84,9 @@ obj-$(CONFIG_PCENGINES_APU2) += pcengine + obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop.o + obj-$(CONFIG_SAMSUNG_Q10) += samsung-q10.o + ++# Shuttle ++obj-$(CONFIG_SHUTTLE_WMI) += shuttle-wmi.o ++ + # Toshiba + obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o + obj-$(CONFIG_TOSHIBA_HAPS) += toshiba_haps.o +diff -Nurp linux-5.15.1/drivers/platform/x86/shuttle-wmi.c linux-5.15.1-shuttle/drivers/platform/x86/shuttle-wmi.c +--- linux-5.15.1/drivers/platform/x86/shuttle-wmi.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.15.1-shuttle/drivers/platform/x86/shuttle-wmi.c 2021-11-08 23:24:45.468092228 +0200 +@@ -0,0 +1,1297 @@ ++/* ++ * ACPI-WMI driver for Shuttle WMI interface ++ * ++ * Copyright (c) 2010 Herton Ronaldo Krzesinski ++ * ++ * Development of this driver was funded by Positivo Informatica S.A. ++ * Parts of the driver were based on some WMI documentation provided by Shuttle ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Herton Ronaldo Krzesinski"); ++MODULE_DESCRIPTION("Shuttle WMI Extras Driver"); ++MODULE_LICENSE("GPL"); ++ ++#define SHUTTLE_WMI_SETGET_GUID "abbc0f6f-8ea1-11d1-00a0-c90629100000" ++#define SHUTTLE_WMI_EVENT_GUID "abbc0f72-8ea1-11d1-00a0-c90629100000" ++MODULE_ALIAS("wmi:"SHUTTLE_WMI_SETGET_GUID); ++MODULE_ALIAS("wmi:"SHUTTLE_WMI_EVENT_GUID); ++ ++#define CMD_WRITEEC 0x00 ++#define CMD_READEC 0x01 ++#define CMD_SCMD 0x02 ++#define CMD_INT15 0x03 ++#define CMD_HWSW 0x07 ++#define CMD_LCTRL 0x09 ++#define CMD_CUTLVDS 0x11 ++#define CMD_MA 0x18 ++#define CMD_DA18IE 0x19 ++#define CMD_DA18IM 0x20 ++ ++#define ECRAM_ER0 0x443 ++#define ECRAM_ER1 0x45a ++#define ECRAM_ER2 0x47b ++#define ECRAM_ER3 0x758 ++#define ECRAM_ER4 0x759 ++ ++struct shuttle_ecram { ++ unsigned short addr; ++ u32 mask; ++}; ++ ++struct shuttle_state { ++ struct shuttle_ecram ecram; ++ struct device_attribute *dev_attr; ++}; ++ ++static struct shuttle_state state_powersave = { ++ .ecram = { ++ .addr = ECRAM_ER3, ++ .mask = 0x10, ++ }, ++}; ++ ++static struct shuttle_state state_touchpad_off = { ++ .ecram = { ++ .addr = ECRAM_ER2, ++ .mask = 0x02, ++ }, ++}; ++ ++static struct shuttle_state state_webcam = { ++ .ecram = { ++ .addr = ECRAM_ER2, ++ .mask = 0x10, ++ }, ++}; ++ ++struct shuttle_rfkill { ++ struct rfkill *rfk; ++ enum rfkill_type type; ++ struct shuttle_ecram ecram_state; ++ struct shuttle_ecram ecram_present; ++ /* lists of rf state switch notification codes */ ++ u32 rf_on[3]; ++ u32 rf_off[3]; ++}; ++ ++static struct shuttle_rfkill srfk_3g = { ++ .type = RFKILL_TYPE_WWAN, ++ .ecram_state = { ++ .addr = ECRAM_ER2, ++ .mask = 0x40, ++ }, ++ .rf_on = { 0x10, 0x29 }, ++ .rf_off = { 0x11, 0x2a }, ++}; ++ ++static struct shuttle_rfkill srfk_bluetooth = { ++ .type = RFKILL_TYPE_BLUETOOTH, ++ .ecram_state = { ++ .addr = ECRAM_ER2, ++ .mask = 0x20, ++ }, ++ .rf_on = { 0x0c, 0x29 }, ++ .rf_off = { 0x0d, 0x2a }, ++}; ++ ++static struct shuttle_rfkill srfk_wlan = { ++ .type = RFKILL_TYPE_WLAN, ++ .ecram_state = { ++ .addr = ECRAM_ER2, ++ .mask = 0x80, ++ }, ++ .ecram_present = { ++ .addr = ECRAM_ER1, ++ .mask = 0x80, ++ }, ++ .rf_on = { 0x08 }, ++ .rf_off = { 0x09 }, ++}; ++ ++enum fn_type { ++ FN_CMD, ++ FN_CMD_DEBUG, ++ FN_RFKILL, ++ FN_STATE ++}; ++ ++struct shuttle_fn_map { ++ char *name; ++ enum fn_type type; ++ unsigned short cmd; ++ unsigned short arg; ++ unsigned short fn; ++ void *data; ++}; ++ ++static struct shuttle_fn_map unknown_fn_map[] = { ++ { "fn_f1", FN_CMD_DEBUG, CMD_SCMD, 0, 0x01, NULL }, ++ { "fn_f2", FN_CMD_DEBUG, CMD_SCMD, 0, 0x02, NULL }, ++ { "fn_f3", FN_CMD_DEBUG, CMD_SCMD, 0, 0x03, NULL }, ++ { "fn_f4", FN_CMD_DEBUG, CMD_SCMD, 0, 0x04, NULL }, ++ { "fn_f5", FN_CMD_DEBUG, CMD_SCMD, 0, 0x05, NULL }, ++ { "fn_f6", FN_CMD_DEBUG, CMD_SCMD, 0, 0x06, NULL }, ++ { "fn_f7", FN_CMD_DEBUG, CMD_SCMD, 0, 0x07, NULL }, ++ { "fn_f8", FN_CMD_DEBUG, CMD_SCMD, 0, 0x08, NULL }, ++ { "fn_f9", FN_CMD_DEBUG, CMD_SCMD, 0, 0x09, NULL }, ++ { "fn_f10", FN_CMD_DEBUG, CMD_SCMD, 0, 0x0a, NULL }, ++ { "fn_f11", FN_CMD_DEBUG, CMD_SCMD, 0, 0x0b, NULL }, ++ { "fn_f12", FN_CMD_DEBUG, CMD_SCMD, 0, 0x0c, NULL }, ++ { "fn_f13", FN_CMD_DEBUG, CMD_SCMD, 0, 0x0d, NULL }, ++ { "fn_f14", FN_CMD_DEBUG, CMD_SCMD, 0, 0x0e, NULL }, ++ { "fn_f15", FN_CMD_DEBUG, CMD_SCMD, 0, 0x0f, NULL }, ++ { "lcd_auto_adjust", FN_CMD, CMD_SCMD, 0, 0x81, NULL }, ++ { "lightbar_brightness_down", FN_CMD_DEBUG, CMD_LCTRL, 1, 0x00, NULL }, ++ { "lightbar_brightness_up", FN_CMD_DEBUG, CMD_LCTRL, 1, 0x01, NULL }, ++ { "panel_set_default", FN_CMD, CMD_SCMD, 0, 0x83, NULL }, ++ { "video_output_on", FN_CMD_DEBUG, CMD_CUTLVDS, 0, 0x01, NULL}, ++ { "video_output_off", FN_CMD_DEBUG, CMD_CUTLVDS, 0, 0x00, NULL}, ++ { "white_balance", FN_CMD, CMD_SCMD, 0, 0x82, NULL }, ++ { } ++}; ++ ++static struct shuttle_fn_map fn_map_1[] = { ++ { "brightness_down", FN_CMD_DEBUG, CMD_SCMD, 0, 0x0b, NULL }, ++ { "brightness_up", FN_CMD_DEBUG, CMD_SCMD, 0, 0x0c, NULL }, ++ { "lcd_auto_adjust", FN_CMD, CMD_SCMD, 0, 0x81, NULL }, ++ { "lightbar_brightness_down", FN_CMD_DEBUG, CMD_LCTRL, 1, 0x00, NULL }, ++ { "lightbar_brightness_up", FN_CMD_DEBUG, CMD_LCTRL, 1, 0x01, NULL }, ++ { "panel_set_default", FN_CMD, CMD_SCMD, 0, 0x83, NULL }, ++ { "powersave", FN_STATE, CMD_SCMD, 0, 0x02, &state_powersave }, ++ { "shuttle_3g", FN_RFKILL, CMD_SCMD, 0, 0x05, &srfk_3g }, ++ { "shuttle_bluetooth", FN_RFKILL, CMD_SCMD, 0, 0x0d, &srfk_bluetooth }, ++ { "shuttle_wlan", FN_RFKILL, CMD_SCMD, 0, 0x04, &srfk_wlan }, ++ { "sleep", FN_CMD_DEBUG, CMD_SCMD, 0, 0x01, NULL }, ++ { "sound_mute", FN_CMD_DEBUG, CMD_SCMD, 0, 0x08, NULL }, ++ { "switch_video", FN_CMD_DEBUG, CMD_SCMD, 0, 0x03, NULL }, ++ { "touchpad_off", FN_STATE, CMD_SCMD, 0, 0x06, &state_touchpad_off }, ++ { "volume_down", FN_CMD_DEBUG, CMD_SCMD, 0, 0x09, NULL }, ++ { "volume_up", FN_CMD_DEBUG, CMD_SCMD, 0, 0x0a, NULL }, ++ { "video_output_on", FN_CMD_DEBUG, CMD_CUTLVDS, 0, 0x01, NULL}, ++ { "video_output_off", FN_CMD_DEBUG, CMD_CUTLVDS, 0, 0x00, NULL}, ++ { "webcam", FN_STATE, CMD_SCMD, 0, 0x07, &state_webcam }, ++ { "white_balance", FN_CMD, CMD_SCMD, 0, 0x82, NULL }, ++ { } ++}; ++ ++static struct shuttle_fn_map fn_map_2[] = { ++ { "brightness_down", FN_CMD_DEBUG, CMD_SCMD, 0, 0x08, NULL }, ++ { "brightness_up", FN_CMD_DEBUG, CMD_SCMD, 0, 0x09, NULL }, ++ { "video_output", FN_CMD_DEBUG, CMD_SCMD, 0, 0x02, NULL }, ++ { "video_output_on", FN_CMD_DEBUG, CMD_CUTLVDS, 0, 0x01, NULL}, ++ { "video_output_off", FN_CMD_DEBUG, CMD_CUTLVDS, 0, 0x00, NULL}, ++ { "shuttle_wlan", FN_RFKILL, CMD_SCMD, 0, 0x0b, &srfk_wlan }, ++ { "sleep", FN_CMD_DEBUG, CMD_SCMD, 0, 0x03, NULL }, ++ { "sound_mute", FN_CMD_DEBUG, CMD_SCMD, 0, 0x04, NULL }, ++ { "switch_video", FN_CMD_DEBUG, CMD_SCMD, 0, 0x07, NULL }, ++ { "touchpad_off", FN_STATE, CMD_SCMD, 0, 0x01, &state_touchpad_off }, ++ { "volume_down", FN_CMD_DEBUG, CMD_SCMD, 0, 0x05, NULL }, ++ { "volume_up", FN_CMD_DEBUG, CMD_SCMD, 0, 0x06, NULL }, ++ { "webcam", FN_STATE, CMD_SCMD, 0, 0x0a, &state_webcam }, ++ { } ++}; ++ ++struct shuttle_backlight { ++ u8 ec_addr; ++ struct shuttle_fn_map *fn_bl_down; ++ struct shuttle_fn_map *fn_bl_up; ++}; ++ ++static struct shuttle_backlight common_bl_desc = { ++ .ec_addr = 0x79, ++}; ++ ++static struct shuttle_backlight quirk_bl_desc = { ++ .ec_addr = 0x79, ++ .fn_bl_down = &fn_map_1[0], ++ .fn_bl_up = &fn_map_1[1], ++}; ++ ++struct shuttle_id { ++ unsigned char cmd_id; ++ const char *model_name; ++ struct shuttle_backlight *bl_desc; ++ struct shuttle_fn_map *fn_map; ++}; ++ ++static struct shuttle_id shuttle_ids[] = { ++ { CMD_MA, "Shuttle MA", &common_bl_desc, fn_map_1 }, ++ { CMD_DA18IE, "Shuttle DA18IE", &quirk_bl_desc, fn_map_1 }, ++ { CMD_DA18IM, "Shuttle DA18IM", &common_bl_desc, fn_map_1 } ++}; ++ ++static struct shuttle_id id_unknown = { ++ .model_name = "Unknown", ++ .fn_map = unknown_fn_map, ++}; ++ ++static struct shuttle_id shuttle_dmi_id; ++ ++static int shuttle_dmi_matched(const struct dmi_system_id *dmi) ++{ ++ shuttle_dmi_id.model_name = dmi->ident; ++ shuttle_dmi_id.bl_desc = &common_bl_desc; ++ shuttle_dmi_id.fn_map = dmi->driver_data; ++ return 1; ++} ++ ++static struct dmi_system_id shuttle_dmi_ids[] = { ++ { ++ .callback = shuttle_dmi_matched, ++ .ident = "Shuttle X50 V2", ++ .matches = { ++ DMI_MATCH(DMI_PRODUCT_NAME, "X50-V2"), ++ }, ++ .driver_data = fn_map_1, ++ }, ++ { ++ .callback = shuttle_dmi_matched, ++ .ident = "Positivo A14IE01", ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "POSITIVO"), ++ DMI_MATCH(DMI_BOARD_NAME, "A14IE01"), ++ }, ++ .driver_data = fn_map_2, ++ }, ++ { ++ .callback = shuttle_dmi_matched, ++ .ident = "Positivo P13", ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "POSITIVO"), ++ DMI_MATCH(DMI_BOARD_NAME, "P13"), ++ }, ++ .driver_data = fn_map_2, ++ }, ++ { ++ .callback = shuttle_dmi_matched, ++ .ident = "Positivo P14", ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "POSITIVO"), ++ DMI_MATCH(DMI_BOARD_NAME, "P14"), ++ }, ++ .driver_data = fn_map_2, ++ }, ++ {} ++}; ++ ++static struct dmi_system_id __devinitdata shuttle_quirk_bl_dmi_ids[] = { ++ { ++ .ident = "Positivo M13", ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "POSITIVO"), ++ DMI_MATCH(DMI_BOARD_NAME, "M13"), ++ }, ++ }, ++ { ++ .ident = "Positivo M14", ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "POSITIVO"), ++ DMI_MATCH(DMI_BOARD_NAME, "M14"), ++ }, ++ }, ++ { ++ .ident = "Positivo A14IM01", ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "POSITIVO"), ++ DMI_MATCH(DMI_BOARD_NAME, "A14IM01"), ++ }, ++ }, ++ { ++ .ident = "Positivo J14IM21", ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "POSITIVO"), ++ DMI_MATCH(DMI_BOARD_NAME, "J14IM21"), ++ }, ++ }, ++ {} ++}; ++ ++struct shuttle_wmi { ++ struct platform_device *pdev; ++ struct shuttle_id *id; ++ struct dentry *dbg_root; ++ struct attribute_group *attr_group; ++ struct input_dev *inputdev; ++ struct backlight_device *bd; ++}; ++ ++struct shuttle_cmd { ++ u16 param2; ++ u16 param1; ++ u8 arg; ++ u8 cmd; ++ u16 hdr; ++}; ++ ++static int wmi_setget_mtd(struct shuttle_cmd *scmd, u32 *res) ++{ ++ acpi_status status; ++ union acpi_object *obj; ++ struct acpi_buffer input; ++ static DEFINE_MUTEX(mtd_lock); ++ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; ++ ++ input.length = sizeof(struct shuttle_cmd); ++ scmd->hdr = 0xec00; ++ input.pointer = (u8 *) scmd; ++ ++ /* We must serialize access to wmi_evaluate_method: the wmi interface ++ * functions in the bios save its parameters on a common shared buffer, ++ * which gets overwritten on parallel calls with unpredicted results; ++ * AML code doesn't have any locking, so we must do this here */ ++ mutex_lock(&mtd_lock); ++ status = wmi_evaluate_method(SHUTTLE_WMI_SETGET_GUID, 0, 2, ++ &input, &output); ++ mutex_unlock(&mtd_lock); ++ if (ACPI_FAILURE(status)) ++ return -1; ++ ++ obj = output.pointer; ++ if (obj) { ++ if (obj->type == ACPI_TYPE_INTEGER) { ++ if (res) ++ *res = obj->integer.value; ++ } else { ++ pr_err("Unsupported object returned (%s)", __func__); ++ res = NULL; ++ } ++ kfree(obj); ++ } else { ++ if (res) { ++ pr_warning("No result from WMI method (%s)", __func__); ++ res = NULL; ++ } ++ } ++ ++ return (res) ? 0 : 1; ++} ++ ++static int wmi_ec_cmd(unsigned char cmd, unsigned char arg, ++ unsigned short param1, unsigned short param2, ++ u32 *res) ++{ ++ struct shuttle_cmd scmd = { ++ .cmd = cmd, ++ .arg = arg, ++ .param1 = param1, ++ .param2 = param2 ++ }; ++ ++ return wmi_setget_mtd(&scmd, res); ++} ++ ++static int wmi_ec_state(struct shuttle_ecram *ecram) ++{ ++ u32 val; ++ ++ if (wmi_ec_cmd(CMD_READEC, 0, 0, ecram->addr, &val)) ++ return -EIO; ++ return (val & ecram->mask) ? 1 : 0; ++} ++ ++static int rfkill_common_set_block(void *data, bool blocked) ++{ ++ int sw; ++ struct shuttle_fn_map *fn_map = data; ++ struct shuttle_rfkill *srfk = fn_map->data; ++ ++ sw = wmi_ec_state(&srfk->ecram_state); ++ if (sw < 0) ++ return sw; ++ ++ if (blocked == sw) ++ wmi_ec_cmd(fn_map->cmd, fn_map->arg, 0, fn_map->fn, NULL); ++ else ++ return 0; ++ ++ sw = wmi_ec_state(&srfk->ecram_state); ++ if (sw < 0) ++ return sw; ++ ++ return (sw != blocked) ? 0 : -EIO; ++} ++ ++static const struct rfkill_ops rfkill_common_ops = { ++ .set_block = rfkill_common_set_block, ++}; ++ ++static void pr_possible_dev_state(void) ++{ ++ static bool pr; ++ u32 val; ++ ++ if (!pr) { ++ pr = true; ++ pr_info("need to unblock some rfkills to check device" ++ " presence\n"); ++ if (!wmi_ec_cmd(CMD_READEC, 0, 0, ECRAM_ER1, &val)) ++ pr_info("possible device present state at address" ++ " 0x%04x is 0x%08x\n", ECRAM_ER1, val); ++ } ++} ++ ++static int shuttle_rfkill_init(struct shuttle_fn_map *fn_map, ++ struct device *dev) ++{ ++ int rc; ++ struct shuttle_rfkill *srfk = fn_map->data; ++ ++ /* Try to detect if device controlled by this rfkill is present, to ++ * avoid having an rfkill switch when not needed */ ++ if (srfk->ecram_present.mask && srfk->ecram_present.addr) { ++ /* we have an address to read to check if device is present */ ++ rc = wmi_ec_state(&srfk->ecram_present); ++ if (rc <= 0) ++ return rc; ++ ++ rc = wmi_ec_state(&srfk->ecram_state); ++ if (rc < 0) ++ return rc; ++ } else { ++ /* print only once the possible value of devices presence, for ++ * extra information (useful to check if really device presence ++ * is or isn't available at usual ECRAM_ER1 address) */ ++ pr_possible_dev_state(); ++ ++ /* no address/mask to check, detect if device is available by ++ * trying to enable it, in case it's disabled */ ++ rc = wmi_ec_state(&srfk->ecram_state); ++ if (rc < 0) ++ return rc; ++ if (!rc) { ++ if (rfkill_common_set_block(fn_map, false)) ++ return 0; ++ ++ /* after check, reset to initial setting; should be ++ * unlikely this returns with error, but really check if ++ * we could reset to initial blocked setting, otherwise ++ * don't make it a fatal error and assume rfkill not ++ * blocked */ ++ if (rfkill_common_set_block(fn_map, true)) ++ rc = 1; ++ } ++ } ++ ++ srfk->rfk = rfkill_alloc(fn_map->name, dev, srfk->type, ++ &rfkill_common_ops, fn_map); ++ if (!srfk->rfk) ++ return -ENOMEM; ++ ++ rfkill_init_sw_state(srfk->rfk, !rc); ++ ++ rc = rfkill_register(srfk->rfk); ++ if (rc) { ++ rfkill_destroy(srfk->rfk); ++ srfk->rfk = NULL; ++ return rc; ++ } ++ ++ return 0; ++} ++ ++static void shuttle_rfkill_remove(struct shuttle_fn_map *fn_map) ++{ ++ struct shuttle_rfkill *srfk = fn_map->data; ++ ++ if (srfk->rfk) { ++ rfkill_unregister(srfk->rfk); ++ rfkill_destroy(srfk->rfk); ++ srfk->rfk = NULL; ++ } ++} ++ ++static int shuttle_rfkill_resume(struct device *dev) ++{ ++ struct shuttle_fn_map *fn_map; ++ struct shuttle_rfkill *srfk; ++ int rc; ++ struct platform_device *pdev = to_platform_device(dev); ++ struct shuttle_wmi *priv = platform_get_drvdata(pdev); ++ ++ for (fn_map = priv->id->fn_map; fn_map->name; fn_map++) { ++ if (fn_map->type != FN_RFKILL) ++ continue; ++ ++ srfk = fn_map->data; ++ if (srfk->rfk) { ++ rc = wmi_ec_state(&srfk->ecram_state); ++ if (rc < 0) ++ return rc; ++ rfkill_set_sw_state(srfk->rfk, rc); ++ } ++ } ++ return 0; ++} ++ ++static bool set_rfkill_sw(u32 *list, u32 code, struct rfkill *rfk, bool blocked) ++{ ++ while (*list) { ++ if (*list == code) { ++ rfkill_set_sw_state(rfk, blocked); ++ return true; ++ } ++ list++; ++ } ++ return false; ++} ++ ++static bool notify_switch_rfkill(struct shuttle_wmi *priv, u32 code) ++{ ++ struct shuttle_fn_map *fn_map; ++ struct shuttle_rfkill *srfk; ++ struct rfkill *rfk; ++ bool res = false; ++ ++ for (fn_map = priv->id->fn_map; fn_map->name; fn_map++) { ++ if (fn_map->type != FN_RFKILL) ++ continue; ++ ++ srfk = fn_map->data; ++ rfk = srfk->rfk; ++ if (!rfk) ++ continue; ++ ++ /* check if notification code means radio turned on, looking ++ * at list_on array of "on" notification codes for this rfkill; ++ * if code is in this list, we notify rfkill core (set_rfkill_sw ++ * does the check, notification and returns true) and we can ++ * skip to next rfkill on the list (some notification codes are ++ * shared, firmware may want to turn on two radios at same time, ++ * so we must check all rfkills with this code) */ ++ if (set_rfkill_sw(srfk->rf_on, code, rfk, false)) { ++ res = true; ++ continue; ++ } ++ ++ /* same as above, but we check the list_off to see if ++ * notification code means radio turned off */ ++ if (set_rfkill_sw(srfk->rf_off, code, rfk, true)) ++ res = true; ++ } ++ /* if we found that notification code was indeed a radio on/off event, ++ * return true here */ ++ return res; ++} ++ ++static bool notify_switch_attr(struct platform_device *pdev, u32 code) ++{ ++ int i; ++ struct shuttle_switch { ++ u32 switch_on; ++ u32 switch_off; ++ char *sys_attr; ++ }; ++ static const struct shuttle_switch codes[] = { ++ { 0x04, 0x05, "touchpad_off" }, ++ { 0x12, 0x13, "webcam" }, ++ { 0x31, 0x32, "powersave" } ++ }; ++ ++ for (i = 0; i < ARRAY_SIZE(codes); i++) { ++ if (codes[i].switch_on == code || codes[i].switch_off == code) { ++ sysfs_notify(&pdev->dev.kobj, NULL, codes[i].sys_attr); ++ return true; ++ } ++ } ++ return false; ++} ++ ++static void shuttle_wmi_notify(u32 value, void *data) ++{ ++ acpi_status status; ++ union acpi_object *obj; ++ u8 type; ++ u32 code; ++ struct acpi_buffer res = { ACPI_ALLOCATE_BUFFER, NULL }; ++ struct shuttle_wmi *priv = data; ++ ++ status = wmi_get_event_data(value, &res); ++ if (status != AE_OK) { ++ pr_warning("unable to retrieve wmi event status" ++ " (error=0x%x)\n", status); ++ return; ++ } ++ ++ obj = (union acpi_object *) res.pointer; ++ if (!obj) ++ return; ++ if (obj->type != ACPI_TYPE_INTEGER) { ++ pr_info("unknown object returned in wmi event\n"); ++ goto notify_exit; ++ } ++ ++ type = (obj->integer.value >> 24) & 0xFF; ++ switch (type) { ++ case 0: /* OSD/Scancode event */ ++ code = obj->integer.value & 0xFFFFFF; ++ ++ /* update rfkill switches */ ++ if (notify_switch_rfkill(priv, code)) ++ break; ++ ++ /* send notification on state switch attributes */ ++ if (notify_switch_attr(priv->pdev, code)) ++ break; ++ ++ if (priv->bd && (code == 0x14 || code == 0x15)) { ++ backlight_force_update(priv->bd, ++ BACKLIGHT_UPDATE_HOTKEY); ++ break; ++ } ++ ++ if (!sparse_keymap_report_event(priv->inputdev, code, 1, true)) ++ pr_info("unhandled scancode (0x%06x)\n", code); ++ break; ++ case 1: /* Power management event */ ++ /* Events not used. ++ * Possible values for obj->integer.value: ++ * 0x01000000 - silent mode ++ * 0x01010000 - brightness sync */ ++ case 2: /* i-PowerXross event */ ++ /* i-PowerXross is a overclocking feature, not ++ * implemented, there are no further details, possible ++ * values for obj->integer.value in documentation: ++ * 0x02000000 - idle mode ++ * 0x02010000 - action mode ++ * 0x02020000 - entry s3 */ ++ break; ++ case 0xec: /* Lost event */ ++ if (printk_ratelimit()) ++ pr_warning("lost event because of buggy BIOS"); ++ break; ++ default: ++ pr_info("unknown wmi notification type (0x%02x)\n", type); ++ } ++ ++notify_exit: ++ kfree(obj); ++} ++ ++static const struct key_entry shuttle_wmi_keymap[] = { ++ { KE_IGNORE, 0x14, { KEY_BRIGHTNESSUP } }, ++ { KE_IGNORE, 0x15, { KEY_BRIGHTNESSDOWN } }, ++ { KE_KEY, 0x16, { KEY_FASTFORWARD } }, ++ { KE_KEY, 0x17, { KEY_REWIND } }, ++ { KE_KEY, 0x18, { KEY_F13 } }, /* OSD Beep */ ++ { KE_KEY, 0x2b, { KEY_F14 } }, /* OSD menu 1 */ ++ { KE_KEY, 0x2c, { KEY_F15 } }, /* OSD menu 2 */ ++ { KE_KEY, 0x2d, { KEY_F16 } }, /* OSD menu 3 */ ++ { KE_KEY, 0x2e, { KEY_F17 } }, /* OSD menu 4 */ ++ { KE_KEY, 0x33, { KEY_F18 } }, /* Update OSD bar status */ ++ { KE_KEY, 0x90, { KEY_WWW } }, ++ { KE_KEY, 0x95, { KEY_PREVIOUSSONG } }, ++ { KE_KEY, 0xa0, { KEY_PROG1 } }, /* Call OSD software */ ++ { KE_KEY, 0xa1, { KEY_VOLUMEDOWN } }, ++ { KE_KEY, 0xa3, { KEY_MUTE } }, ++ { KE_KEY, 0xb2, { KEY_VOLUMEUP } }, ++ { KE_KEY, 0xb4, { KEY_PLAYPAUSE } }, ++ { KE_KEY, 0xbb, { KEY_STOPCD } }, ++ { KE_KEY, 0xc8, { KEY_MAIL } }, ++ { KE_KEY, 0xcd, { KEY_NEXTSONG } }, ++ { KE_KEY, 0xd0, { KEY_MEDIA } }, ++ ++ /* Known non hotkey events don't handled, that we don't care or ++ * which we must ignore */ ++ { KE_IGNORE, 0x01, }, /* Caps Lock toggled */ ++ { KE_IGNORE, 0x02, }, /* Num Lock toggled */ ++ { KE_IGNORE, 0x03, }, /* Scroll Lock toggled */ ++ { KE_IGNORE, 0x06, }, /* Downclock/Silent on */ ++ { KE_IGNORE, 0x07, }, /* Downclock/Silent off */ ++ { KE_IGNORE, 0x0a, }, /* WiMax on */ ++ { KE_IGNORE, 0x0b, }, /* WiMax off */ ++ { KE_IGNORE, 0x0e, }, /* RF on */ ++ { KE_IGNORE, 0x0f, }, /* RF off */ ++ { KE_IGNORE, 0x1a, }, /* Auto Brightness on */ ++ { KE_IGNORE, 0x1b, }, /* Auto Brightness off */ ++ { KE_IGNORE, 0x1c, }, /* Auto-KB Brightness on */ ++ { KE_IGNORE, 0x1d, }, /* Auto-KB Brightness off */ ++ { KE_IGNORE, 0x1e, }, /* Light Bar Brightness up */ ++ { KE_IGNORE, 0x1f, }, /* Light Bar Brightness down */ ++ { KE_IGNORE, 0x20, }, /* China Telecom AP enable */ ++ { KE_IGNORE, 0x21, }, /* China Mobile AP enable */ ++ { KE_IGNORE, 0x22, }, /* Huawei AP enable */ ++ { KE_IGNORE, 0x23, }, /* Docking in */ ++ { KE_IGNORE, 0x24, }, /* Docking out */ ++ { KE_IGNORE, 0x25, }, /* Device no function */ ++ { KE_IGNORE, 0x26, }, /* i-PowerXross OverClocking */ ++ { KE_IGNORE, 0x27, }, /* i-PowerXross PowerSaving */ ++ { KE_IGNORE, 0x28, }, /* i-PowerXross off */ ++ { KE_IGNORE, 0x2f, }, /* Optimus on */ ++ { KE_IGNORE, 0x30, }, /* Optimus off */ ++ { KE_IGNORE, 0x91, }, /* ICO 2 on */ ++ { KE_IGNORE, 0x92, }, /* ICO 2 off */ ++ ++ { KE_END, 0 } ++}; ++ ++static int shuttle_wmi_input_init(struct shuttle_wmi *priv) ++{ ++ struct input_dev *input; ++ int rc; ++ ++ input = input_allocate_device(); ++ if (!input) ++ return -ENOMEM; ++ ++ input->name = "Shuttle WMI hotkeys"; ++ input->phys = KBUILD_MODNAME "/input0"; ++ input->id.bustype = BUS_HOST; ++ ++ rc = sparse_keymap_setup(input, shuttle_wmi_keymap, NULL); ++ if (rc) ++ goto err_free_dev; ++ ++ rc = input_register_device(input); ++ if (rc) ++ goto err_free_keymap; ++ ++ priv->inputdev = input; ++ return 0; ++ ++err_free_keymap: ++ sparse_keymap_free(input); ++err_free_dev: ++ input_free_device(input); ++ return rc; ++} ++ ++static void shuttle_wmi_input_remove(struct shuttle_wmi *priv) ++{ ++ struct input_dev *input = priv->inputdev; ++ ++ sparse_keymap_free(input); ++ input_unregister_device(input); ++} ++ ++static int shuttle_wmi_get_bl(struct backlight_device *bd) ++{ ++ u8 val; ++ int rc; ++ struct shuttle_wmi *priv = bl_get_data(bd); ++ struct shuttle_backlight *sbl = priv->id->bl_desc; ++ ++ rc = ec_read(sbl->ec_addr, &val); ++ if (rc) ++ return rc; ++ return val & 7; ++} ++ ++static int shuttle_wmi_update_bl(struct backlight_device *bd) ++{ ++ int rc, steps; ++ u8 val; ++ struct shuttle_fn_map *fn_down, *fn_up; ++ struct shuttle_wmi *priv = bl_get_data(bd); ++ struct shuttle_backlight *sbl = priv->id->bl_desc; ++ ++ fn_down = sbl->fn_bl_down; ++ fn_up = sbl->fn_bl_up; ++ if (!fn_down || !fn_up) { ++ rc = ec_write(sbl->ec_addr, bd->props.brightness); ++ if (rc) ++ return rc; ++ } else { ++ /* change brightness by steps, this is a quirk for shuttle ++ * machines which don't accept direct write to ec for this */ ++ rc = ec_read(sbl->ec_addr, &val); ++ if (rc) ++ return rc; ++ steps = bd->props.brightness - (val & 7); ++ while (steps > 0) { ++ wmi_ec_cmd(fn_up->cmd, fn_up->arg, 0, fn_up->fn, NULL); ++ steps--; ++ } ++ while (steps < 0) { ++ wmi_ec_cmd(fn_down->cmd, fn_down->arg, 0, fn_down->fn, ++ NULL); ++ steps++; ++ } ++ } ++ ++ wmi_ec_cmd(CMD_CUTLVDS, 0, 0, ++ (bd->props.power == FB_BLANK_UNBLANK) ? 1 : 0, ++ NULL); ++ ++ return 0; ++} ++ ++static const struct backlight_ops shuttle_wmi_bl_ops = { ++ .get_brightness = shuttle_wmi_get_bl, ++ .update_status = shuttle_wmi_update_bl, ++}; ++ ++static int shuttle_wmi_backlight_init(struct shuttle_wmi *priv) ++{ ++ int rc; ++ u8 val; ++ struct backlight_properties props; ++ struct backlight_device *bd; ++ struct shuttle_backlight *sbl = priv->id->bl_desc; ++ ++ rc = ec_read(sbl->ec_addr, &val); ++ if (rc) ++ return rc; ++ memset(&props, 0, sizeof(struct backlight_properties)); ++ props.max_brightness = 7; ++ props.brightness = val & 7; ++ props.power = FB_BLANK_UNBLANK; ++ ++ bd = backlight_device_register(KBUILD_MODNAME, &priv->pdev->dev, priv, ++ &shuttle_wmi_bl_ops, &props); ++ if (IS_ERR(bd)) ++ return PTR_ERR(bd); ++ priv->bd = bd; ++ return 0; ++} ++ ++static void shuttle_wmi_backlight_exit(struct shuttle_wmi *priv) ++{ ++ if (priv->bd) ++ backlight_device_unregister(priv->bd); ++} ++ ++static ssize_t store_fn_cmd(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct shuttle_wmi *priv = platform_get_drvdata(pdev); ++ struct shuttle_fn_map *fn_map; ++ ++ for (fn_map = priv->id->fn_map; fn_map->name; fn_map++) { ++ if (fn_map->name == attr->attr.name) { ++ wmi_ec_cmd(fn_map->cmd, fn_map->arg, 0, fn_map->fn, ++ NULL); ++ return count; ++ } ++ } ++ return -EIO; ++} ++ ++static int set_fn_cmd_debug(void *data, u64 val) ++{ ++ struct shuttle_fn_map *fn_map = data; ++ ++ wmi_ec_cmd(fn_map->cmd, fn_map->arg, 0, fn_map->fn, NULL); ++ /* we don't know yet how many brightness values or maximum brightness ++ * values for lightbar, for now print possible brightness value change ++ * to aid in discovering these */ ++ if (fn_map->cmd == CMD_LCTRL) { ++ u32 val; ++ if (!wmi_ec_cmd(CMD_READEC, 0, 0, ECRAM_ER4, &val)) ++ pr_info("possible lightbar brightness change to value" ++ " 0x%08x\n", val); ++ } ++ return 0; ++} ++DEFINE_SIMPLE_ATTRIBUTE(fops_fn_cmd_debug, NULL, set_fn_cmd_debug, "%llu"); ++ ++static ssize_t show_fn_state(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct shuttle_fn_map *fn_map; ++ struct shuttle_state *state; ++ int sw; ++ struct platform_device *pdev = to_platform_device(dev); ++ struct shuttle_wmi *priv = platform_get_drvdata(pdev); ++ ++ for (fn_map = priv->id->fn_map; fn_map->name; fn_map++) { ++ if (fn_map->name != attr->attr.name) ++ continue; ++ ++ state = fn_map->data; ++ sw = wmi_ec_state(&state->ecram); ++ if (sw < 0) ++ return sw; ++ return sprintf(buf, "%d\n", sw); ++ } ++ return -EIO; ++} ++ ++static ssize_t store_fn_state(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int enable, sw; ++ struct shuttle_fn_map *fn_map; ++ struct shuttle_state *state; ++ struct platform_device *pdev = to_platform_device(dev); ++ struct shuttle_wmi *priv = platform_get_drvdata(pdev); ++ ++ if (sscanf(buf, "%i", &enable) != 1) ++ return -EINVAL; ++ ++ for (fn_map = priv->id->fn_map; fn_map->name; fn_map++) { ++ if (fn_map->name != attr->attr.name) ++ continue; ++ ++ state = fn_map->data; ++ sw = wmi_ec_state(&state->ecram); ++ if (sw < 0) ++ return sw; ++ enable = enable ? 1 : 0; ++ if (enable != sw) { ++ wmi_ec_cmd(fn_map->cmd, fn_map->arg, 0, fn_map->fn, ++ NULL); ++ sw = wmi_ec_state(&state->ecram); ++ if (sw < 0) ++ return sw; ++ if (enable != sw) ++ return -EIO; ++ } ++ return count; ++ } ++ return -EIO; ++} ++ ++static void shuttle_fn_exit(struct shuttle_wmi *priv) ++{ ++ struct shuttle_fn_map *fn_map; ++ struct dentry *dbg_entry; ++ struct shuttle_state *state; ++ ++ if (priv->attr_group) { ++ sysfs_remove_group(&priv->pdev->dev.kobj, priv->attr_group); ++ kfree(priv->attr_group->attrs); ++ kfree(priv->attr_group); ++ priv->attr_group = NULL; ++ } ++ ++ fn_map = priv->id->fn_map; ++ while (fn_map->name) { ++ switch (fn_map->type) { ++ case FN_CMD: ++ kfree(fn_map->data); ++ fn_map->data = NULL; ++ break; ++ case FN_CMD_DEBUG: ++ dbg_entry = fn_map->data; ++ if (dbg_entry) { ++ debugfs_remove(dbg_entry); ++ fn_map->data = NULL; ++ } ++ break; ++ case FN_RFKILL: ++ shuttle_rfkill_remove(fn_map); ++ break; ++ case FN_STATE: ++ state = fn_map->data; ++ kfree(state->dev_attr); ++ state->dev_attr = NULL; ++ break; ++ } ++ fn_map++; ++ } ++} ++ ++static struct device_attribute *new_dev_attr(struct shuttle_fn_map *fn_map) ++{ ++ struct device_attribute *dev_attr; ++ ++ dev_attr = kzalloc(sizeof(struct device_attribute), GFP_KERNEL); ++ if (!dev_attr) ++ return NULL; ++ dev_attr->attr.name = fn_map->name; ++ return dev_attr; ++} ++ ++static int shuttle_fn_init(struct shuttle_wmi *priv) ++{ ++ struct shuttle_fn_map *fn_map; ++ struct device_attribute *dev_attr; ++ struct dentry *dbg_entry; ++ struct shuttle_state *state; ++ struct attribute **attr; ++ int nattr = 0; ++ int rc = -ENOMEM; ++ ++ fn_map = priv->id->fn_map; ++ while (fn_map->name) { ++ switch (fn_map->type) { ++ case FN_CMD: ++ dev_attr = new_dev_attr(fn_map); ++ if (!dev_attr) ++ goto fn_init_err; ++ dev_attr->attr.mode = 0200; ++ dev_attr->store = store_fn_cmd; ++ fn_map->data = dev_attr; ++ nattr++; ++ break; ++ case FN_CMD_DEBUG: ++ dbg_entry = debugfs_create_file(fn_map->name, 0200, ++ priv->dbg_root, fn_map, ++ &fops_fn_cmd_debug); ++ if (!dbg_entry) ++ goto fn_init_err; ++ fn_map->data = dbg_entry; ++ break; ++ case FN_RFKILL: ++ rc = shuttle_rfkill_init(fn_map, &priv->pdev->dev); ++ if (rc) ++ goto fn_init_err; ++ break; ++ case FN_STATE: ++ dev_attr = new_dev_attr(fn_map); ++ if (!dev_attr) ++ goto fn_init_err; ++ dev_attr->attr.mode = 0644; ++ dev_attr->show = show_fn_state; ++ dev_attr->store = store_fn_state; ++ state = fn_map->data; ++ state->dev_attr = dev_attr; ++ nattr++; ++ break; ++ } ++ fn_map++; ++ } ++ ++ /* create array of sysfs attributes (FN_CMD and FN_STATE types) */ ++ if (nattr > 0) { ++ priv->attr_group = kzalloc(sizeof(struct attribute_group), ++ GFP_KERNEL); ++ if (!priv->attr_group) ++ goto fn_init_err; ++ priv->attr_group->attrs = kzalloc(sizeof(struct attribute *) * ++ (nattr + 1), GFP_KERNEL); ++ if (!priv->attr_group->attrs) ++ goto fn_attrs_err; ++ attr = priv->attr_group->attrs; ++ fn_map = priv->id->fn_map; ++ while (fn_map->name) { ++ if (fn_map->type == FN_CMD) { ++ dev_attr = fn_map->data; ++ *attr = &dev_attr->attr; ++ attr++; ++ } else if (fn_map->type == FN_STATE) { ++ state = fn_map->data; ++ *attr = &state->dev_attr->attr; ++ attr++; ++ } ++ fn_map++; ++ } ++ rc = sysfs_create_group(&priv->pdev->dev.kobj, ++ priv->attr_group); ++ if (rc) ++ goto fn_grp_err; ++ } ++ ++ return 0; ++ ++fn_grp_err: ++ kfree(priv->attr_group->attrs); ++fn_attrs_err: ++ kfree(priv->attr_group); ++ priv->attr_group = NULL; ++fn_init_err: ++ shuttle_fn_exit(priv); ++ return rc; ++} ++ ++static int __devinit shuttle_wmi_probe(struct platform_device *pdev) ++{ ++ struct shuttle_wmi *priv; ++ int rc, i; ++ acpi_status status; ++ u32 val; ++ ++ priv = kzalloc(sizeof(struct shuttle_wmi), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ priv->pdev = pdev; ++ platform_set_drvdata(pdev, priv); ++ ++ for (i = 0; i < ARRAY_SIZE(shuttle_ids); i++) { ++ rc = wmi_ec_cmd(shuttle_ids[i].cmd_id, 0, 0, 0, &val); ++ if (!rc && val == 1) { ++ priv->id = &shuttle_ids[i]; ++ break; ++ } ++ } ++ /* If we can't identify the system using a WMI command, try using a DMI ++ * match, otherwise set id to unknown model */ ++ if (i == ARRAY_SIZE(shuttle_ids)) { ++ if (dmi_check_system(shuttle_dmi_ids)) ++ priv->id = &shuttle_dmi_id; ++ else ++ priv->id = &id_unknown; ++ } ++ ++ /* Process backlight quirks for some models based on DA18IM */ ++ if (priv->id->cmd_id == CMD_DA18IM) { ++ if (dmi_check_system(shuttle_quirk_bl_dmi_ids)) ++ priv->id->bl_desc = &quirk_bl_desc; ++ } ++ ++ priv->dbg_root = debugfs_create_dir(KBUILD_MODNAME, NULL); ++ if (!priv->dbg_root) { ++ rc = -ENOMEM; ++ goto err_debugfs; ++ } ++ ++ rc = shuttle_fn_init(priv); ++ if (rc) ++ goto err_fn; ++ ++ rc = shuttle_wmi_input_init(priv); ++ if (rc) ++ goto err_input; ++ ++ status = wmi_install_notify_handler(SHUTTLE_WMI_EVENT_GUID, ++ shuttle_wmi_notify, priv); ++ if (ACPI_FAILURE(status)) { ++ rc = -EIO; ++ goto err_notify; ++ } ++ ++ if (!acpi_video_backlight_support()) { ++ rc = shuttle_wmi_backlight_init(priv); ++ if (rc) ++ goto err_backlight; ++ } ++ return 0; ++ ++err_backlight: ++ wmi_remove_notify_handler(SHUTTLE_WMI_EVENT_GUID); ++err_notify: ++ shuttle_wmi_input_remove(priv); ++err_input: ++ shuttle_fn_exit(priv); ++err_fn: ++ debugfs_remove(priv->dbg_root); ++err_debugfs: ++ kfree(priv); ++ return rc; ++} ++ ++static int __devexit shuttle_wmi_remove(struct platform_device *pdev) ++{ ++ struct shuttle_wmi *priv = platform_get_drvdata(pdev); ++ ++ shuttle_wmi_backlight_exit(priv); ++ wmi_remove_notify_handler(SHUTTLE_WMI_EVENT_GUID); ++ shuttle_wmi_input_remove(priv); ++ shuttle_fn_exit(priv); ++ debugfs_remove(priv->dbg_root); ++ kfree(priv); ++ return 0; ++} ++ ++static int shuttle_wmi_resume(struct device *dev) ++{ ++ return shuttle_rfkill_resume(dev); ++} ++ ++static const struct dev_pm_ops shuttle_wmi_pm_ops = { ++ .restore = shuttle_wmi_resume, ++ .resume = shuttle_wmi_resume, ++}; ++ ++static struct platform_driver shuttle_wmi_driver = { ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .owner = THIS_MODULE, ++ .pm = &shuttle_wmi_pm_ops, ++ }, ++ .probe = shuttle_wmi_probe, ++ .remove = __devexit_p(shuttle_wmi_remove), ++}; ++ ++static struct platform_device *shuttle_wmi_device; ++ ++static ssize_t show_model_name(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct shuttle_wmi *priv = platform_get_drvdata(pdev); ++ ++ return sprintf(buf, "%s\n", priv->id->model_name); ++} ++ ++static DEVICE_ATTR(model_name, 0444, show_model_name, NULL); ++ ++static struct attribute *shuttle_platform_attributes[] = { ++ &dev_attr_model_name.attr, ++ NULL ++}; ++ ++static struct attribute_group shuttle_attribute_group = { ++ .attrs = shuttle_platform_attributes ++}; ++ ++static int __init shuttle_wmi_init(void) ++{ ++ int rc; ++ u32 val; ++ ++ if (!wmi_has_guid(SHUTTLE_WMI_SETGET_GUID) || ++ !wmi_has_guid(SHUTTLE_WMI_EVENT_GUID)) { ++ pr_err("Required WMI GUID not available\n"); ++ return -ENODEV; ++ } ++ ++ /* Check that we are really on a shuttle BIOS */ ++ rc = wmi_ec_cmd(CMD_INT15, 0, 0, 0, &val); ++ if (rc || val != 0x534c) { ++ pr_err("Shuttle WMI device not found or unsupported" ++ " (val=0x%08x)\n", val); ++ return -ENODEV; ++ } ++ ++ rc = platform_driver_register(&shuttle_wmi_driver); ++ if (rc) ++ goto err_driver_register; ++ shuttle_wmi_device = platform_device_alloc(KBUILD_MODNAME, -1); ++ if (!shuttle_wmi_device) { ++ rc = -ENOMEM; ++ goto err_device_alloc; ++ } ++ rc = platform_device_add(shuttle_wmi_device); ++ if (rc) ++ goto err_device_add; ++ ++ rc = sysfs_create_group(&shuttle_wmi_device->dev.kobj, ++ &shuttle_attribute_group); ++ if (rc) ++ goto err_sysfs; ++ ++ return 0; ++ ++err_sysfs: ++ platform_device_del(shuttle_wmi_device); ++err_device_add: ++ platform_device_put(shuttle_wmi_device); ++err_device_alloc: ++ platform_driver_unregister(&shuttle_wmi_driver); ++err_driver_register: ++ return rc; ++} ++ ++static void __exit shuttle_wmi_exit(void) ++{ ++ sysfs_remove_group(&shuttle_wmi_device->dev.kobj, ++ &shuttle_attribute_group); ++ platform_device_unregister(shuttle_wmi_device); ++ platform_driver_unregister(&shuttle_wmi_driver); ++} ++ ++module_init(shuttle_wmi_init); ++module_exit(shuttle_wmi_exit); +diff -Nurp linux-5.15.1/MAINTAINERS linux-5.15.1-shuttle/MAINTAINERS +--- linux-5.15.1/MAINTAINERS 2021-10-31 22:53:10.000000000 +0200 ++++ linux-5.15.1-shuttle/MAINTAINERS 2021-11-08 23:24:45.469092275 +0200 +@@ -16993,6 +16993,12 @@ S: Orphan + F: drivers/media/platform/sh_vou.c + F: include/media/drv-intf/sh_vou.h + ++SHUTTLE WMI EXTRAS DRIVER ++M: Herton Ronaldo Krzesinski ++L: platform-driver-x86@vger.kernel.org ++S: Maintained ++F: drivers/platform/x86/shuttle-wmi.c ++ + SI2157 MEDIA DRIVER + M: Antti Palosaari + L: linux-media@vger.kernel.org diff --git a/kernel/tools/perf/files/patches/mageia/platform-x86-shuttle-wmi-4.13-buildfix.patch b/kernel/tools/perf/files/patches/mageia/platform-x86-shuttle-wmi-4.13-buildfix.patch new file mode 100644 index 0000000000..c9a1c60dba --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/platform-x86-shuttle-wmi-4.13-buildfix.patch @@ -0,0 +1,30 @@ + +sparse_keymap_free() is now obsolete. + +Signed-off-by: Thomas Backlund + +--- linux/drivers/platform/x86/shuttle-wmi.c.orig 2017-10-15 00:39:53.041395980 +0300 ++++ linux/drivers/platform/x86/shuttle-wmi.c 2017-10-15 01:05:37.008662881 +0300 +@@ -763,14 +763,9 @@ static int shuttle_wmi_input_init(struct + goto err_free_dev; + + rc = input_register_device(input); +- if (rc) +- goto err_free_keymap; + + priv->inputdev = input; + return 0; +- +-err_free_keymap: +- sparse_keymap_free(input); + err_free_dev: + input_free_device(input); + return rc; +@@ -780,7 +775,6 @@ static void shuttle_wmi_input_remove(str + { + struct input_dev *input = priv->inputdev; + +- sparse_keymap_free(input); + input_unregister_device(input); + } + diff --git a/kernel/tools/perf/files/patches/mageia/platform-x86-shuttle-wmi-4.2-buildfix.patch b/kernel/tools/perf/files/patches/mageia/platform-x86-shuttle-wmi-4.2-buildfix.patch new file mode 100644 index 0000000000..ee0d5849a3 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/platform-x86-shuttle-wmi-4.2-buildfix.patch @@ -0,0 +1,19 @@ +--- linux/drivers/platform/x86/shuttle-wmi.c.orig 2015-09-30 00:51:13.000000000 +0300 ++++ linux/drivers/platform/x86/shuttle-wmi.c 2015-09-30 02:04:20.808458393 +0300 +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + MODULE_AUTHOR("Herton Ronaldo Krzesinski"); + MODULE_DESCRIPTION("Shuttle WMI Extras Driver"); +@@ -1161,7 +1162,7 @@ static int shuttle_wmi_probe(struct plat + goto err_notify; + } + +- if (!acpi_video_backlight_support()) { ++ if (acpi_video_get_backlight_type() == acpi_backlight_vendor) { + rc = shuttle_wmi_backlight_init(priv); + if (rc) + goto err_backlight; diff --git a/kernel/tools/perf/files/patches/mageia/platform-x86-shuttle-wmi-drop-devinit-exit.patch b/kernel/tools/perf/files/patches/mageia/platform-x86-shuttle-wmi-drop-devinit-exit.patch new file mode 100644 index 0000000000..171286414e --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/platform-x86-shuttle-wmi-drop-devinit-exit.patch @@ -0,0 +1,38 @@ +--- ./drivers/platform/x86/shuttle-wmi.c.orig 2013-01-16 18:13:57.000000000 +0200 ++++ ./drivers/platform/x86/shuttle-wmi.c 2013-01-16 18:41:13.676433242 +0200 +@@ -294,7 +294,7 @@ static struct dmi_system_id shuttle_dmi_ + {} + }; + +-static struct dmi_system_id __devinitdata shuttle_quirk_bl_dmi_ids[] = { ++static struct dmi_system_id shuttle_quirk_bl_dmi_ids[] = { + { + .ident = "Positivo M13", + .matches = { +@@ -1105,7 +1105,7 @@ fn_init_err: + return rc; + } + +-static int __devinit shuttle_wmi_probe(struct platform_device *pdev) ++static int shuttle_wmi_probe(struct platform_device *pdev) + { + struct shuttle_wmi *priv; + int rc, i; +@@ -1181,7 +1181,7 @@ err_debugfs: + return rc; + } + +-static int __devexit shuttle_wmi_remove(struct platform_device *pdev) ++static int shuttle_wmi_remove(struct platform_device *pdev) + { + struct shuttle_wmi *priv = platform_get_drvdata(pdev); + +@@ -1211,7 +1211,7 @@ static struct platform_driver shuttle_wm + .pm = &shuttle_wmi_pm_ops, + }, + .probe = shuttle_wmi_probe, +- .remove = __devexit_p(shuttle_wmi_remove), ++ .remove = shuttle_wmi_remove, + }; + + static struct platform_device *shuttle_wmi_device; diff --git a/kernel/tools/perf/files/patches/mageia/platform-x86-shuttle-wmi-kernel-5.5.patch b/kernel/tools/perf/files/patches/mageia/platform-x86-shuttle-wmi-kernel-5.5.patch new file mode 100644 index 0000000000..23b379a101 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/platform-x86-shuttle-wmi-kernel-5.5.patch @@ -0,0 +1,35 @@ + +pr_warning is now pr_warn + +Signed-off-by: Thomas Backlund + + +--- ./drivers/platform/x86/shuttle-wmi.c.orig 2020-02-03 17:22:16.374611323 +0200 ++++ ./drivers/platform/x86/shuttle-wmi.c 2020-02-03 18:19:03.663898669 +0200 +@@ -379,7 +379,7 @@ static int wmi_setget_mtd(struct shuttle + kfree(obj); + } else { + if (res) { +- pr_warning("No result from WMI method (%s)", __func__); ++ pr_warn("No result from WMI method (%s)", __func__); + res = NULL; + } + } +@@ -628,7 +628,7 @@ static void shuttle_wmi_notify(u32 value + + status = wmi_get_event_data(value, &res); + if (status != AE_OK) { +- pr_warning("unable to retrieve wmi event status" ++ pr_warn("unable to retrieve wmi event status" + " (error=0x%x)\n", status); + return; + } +@@ -678,7 +678,7 @@ static void shuttle_wmi_notify(u32 value + break; + case 0xec: /* Lost event */ + if (printk_ratelimit()) +- pr_warning("lost event because of buggy BIOS"); ++ pr_warn("lost event because of buggy BIOS"); + break; + default: + pr_info("unknown wmi notification type (0x%02x)\n", type); diff --git a/kernel/tools/perf/pspec.xml b/kernel/tools/perf/pspec.xml index c5ffd5fe9d..43648e1a23 100644 --- a/kernel/tools/perf/pspec.xml +++ b/kernel/tools/perf/pspec.xml @@ -12,7 +12,7 @@ app:gui Performance analyser tool that makes full use of the Linux performance counter subsystem perf is a new tool which is used to optimize, validate and measure applications, workloads or the full system through the Linux performance counter subsystem. - https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-5.10.tar.gz + https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-5.15.tar.gz libunwind-devel audit-devel @@ -42,46 +42,65 @@ - patches/linux/patch-5.10.45.xz + patches/linux/patch-5.15.41.xz + + + patches/aufs5/aufs5.15.36-20220509.patch + patches/aufs5/aufs5-base.patch + patches/aufs5/aufs5-kbuild.patch + patches/aufs5/aufs5-loopback.patch + patches/aufs5/aufs5-mmap.patch + patches/aufs5/tmpfs-idr.patch + patches/aufs5/vfs-ino.patch + patches/aufs5/aufs5-standalone.patch + - patches/mageia/fs-aufs5.10.patch - patches/mageia/fs-aufs5.10-symbol-exports.patch - patches/mageia/fs-aufs5.10-tristate.patch + patches/mageia/fs-procfs-do-not-list-TID-0-in-proc-pid-task.patch + patches/mageia/CVE-2019-12379.patch patches/mageia/CVE-2020-16119-DCCP-CCID-structure-use-after-free.patch - + + patches/mageia/platform-x86-add-shuttle-wmi-driver.patch + patches/mageia/platform-x86-shuttle-wmi-drop-devinit-exit.patch + patches/mageia/platform-x86-shuttle-wmi-4.2-buildfix.patch + patches/mageia/platform-x86-shuttle-wmi-4.13-buildfix.patch + patches/mageia/platform-x86-shuttle-wmi-kernel-5.5.patch + patches/mageia/3rd-3rdparty-tree.patch patches/mageia/3rd-3rdparty-merge.patch - + patches/mageia/3rd-ndiswrapper-1.63.patch patches/mageia/3rd-ndiswrapper-Kconfig.patch patches/mageia/3rd-ndiswrapper-Makefile-build-fix.patch patches/mageia/3rd-niswrapper-Kconfig-Makefile.patch - + patches/mageia/3rd-rtl8812au.patch patches/mageia/3rd-rtl8812au-Kconfig-Makefile.patch patches/mageia/3rd-rtl8812au-rename.patch - patches/mageia/3rd-rtl8812au-kernel-5.10.patch - + patches/mageia/3rd-rtl8812au-kernel-5.12.patch + patches/mageia/3rd-rtl8812au-kernel-5.15.patch + patches/mageia/3rd-rtl8723de.patch patches/mageia/3rd-rtl8723de-Kconfig-Makefile.patch patches/mageia/3rd-rtl8723de-fix-redefine.patch patches/mageia/3rd-rtl8723de-nodebug.patch patches/mageia/3rd-rtl8223de-kernel-5.6.patch patches/mageia/3rd-rtl8723de-add-kernel-5.8-support.patch - + patches/mageia/3rd-viahss-0.92.patch patches/mageia/3rd-viahss-config.patch patches/mageia/3rd-viahss-module-license.patch patches/mageia/3rd-viahss-2.6.35-buildfix.patch patches/mageia/3rd-viahss-3.0-buildfix.patch patches/mageia/3rd-viahss-Kconfig-Makefile.patch - + patches/mageia/3rd-rtl8821ce.patch patches/mageia/3rd-rtl8821ce-Kconfig-Makefile.patch patches/mageia/3rd-rtl8821ce-5.8-fix.patch patches/mageia/3rd-rtl8821ce-kernel-5.10.patch - + patches/mageia/3rd-rtl8821ce-kernel-5.12.patch + patches/mageia/3rd-rtl8821ce-kernel-5.15.patch + patches/mageia/3rd-fix-kconfig.patch @@ -116,6 +135,13 @@ + + 2022-05-21 + 5.15.41 + Version bump. + Mustafa Cinasal + muscnsl@gmail.com + 2021-06-19 5.10.45